WildByDesign Posted September 18 Posted September 18 (edited) I've been working on a lightweight Notepad clone off and on, but haven't had time to complete it. I really like the classic win32 Notepad but needed dark mode. Please keep in mind that this is not complete. If anyone wants to add features and help carry the project forward, please feel free. Working so far: Open text files Toggle between dark mode and light mode Zoom In, Zoom Out, and Restore Default Zoom Enable/Disable Word Wrap Statusbar that actively shows the line number and column I still have to figure out how to do a Save As dialog like Notepad has where you get to select the text encoding. There is a lot missing. The problem is that I have other projects that are higher priority than this Notepad clone project. So I am not 100% sure if or when I will get a chance to finish it. But I am always to have anyone collaborate on it. Notepad-2026.09.28b.zip Notepad-2026.09.29.zip Notepad-2026.09.30.zip Edited September 30 by WildByDesign Updated release source MattyD and argumentum 2
argumentum Posted September 18 Posted September 18 ..as is should be called text viewer, unless you add a simple "save" ( even without the save as ) WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
MattyD Posted September 25 Posted September 25 Hope you don't mind, but I've added a few bits and bobs for fun. (take or leave it ) expandcollapse popup#include <FileConstants.au3> #include <FontConstants.au3> #include <MsgBoxConstants.au3> #include <WinAPIGdi.au3> #include <WindowsStylesConstants.au3> #include <GUIConstantsEx.au3> #include <EditConstants.au3> #include <GuiStatusBar.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include "GUIDarkTheme.au3" #include "GuiEditEx.au3" ;Virtual key - the definition probably exists in a standard include library somewhere, but I'm too lazy to find it atm. ;Used to monitor control-wheel zooming. Global Const $MK_CONTROL = 0x0008 ; DPI awareness - nit-picky, but no magic numbers! DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ;Or technically this is a bit better because the DPI_AWARENESS_CONTEXT type is a pseudo-handle - not a signed int. ;~ Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = Ptr(-4) ;~ DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "handle", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ;{+} is the key on the top row, which you need "shift" to get to. ;So we should use "=" for zooming in here, or {NUMPADADD} for the other "plus" key. HotKeySet("^=", "_ZoomIn") HotKeySet("^{NUMPADADD}", "_ZoomIn") HotKeySet("^-", "_ZoomOut") HotKeySet("^{NUMPADSUB}", "_ZoomOut") HotKeySet("^0", "RestoreZoom") Global $g_iBaseFontSize = 11, $g_sSelFontFamily = "Consolas" Global $g_hGUI, $g_idEdit, $g_hEdit, $g_hStatus, $g_idWordWrap Global $g_hSubclassCallback = 0 Notepad() Func Notepad() Local $aWinDims[2] = [760, 500] _ScaleVals($aWinDims) $g_hGUI = GUICreate("Notepad", $aWinDims[0], $aWinDims[1], -1, -1, $WS_OVERLAPPEDWINDOW) Local $idFileMenu = GUICtrlCreateMenu("&File") Local $idOpen = GUICtrlCreateMenuItem("&Open...", $idFileMenu) Local $idExit = GUICtrlCreateMenuItem("E&xit", $idFileMenu) Local $idEditMenu = GUICtrlCreateMenu("&Edit") Local $idFormatMenu = GUICtrlCreateMenu("&Format") Local $idViewMenu = GUICtrlCreateMenu("&View") Local $idHelpMenu = GUICtrlCreateMenu("&Help") $g_idWordWrap = GUICtrlCreateMenuItem('Word &Wrap', $idFormatMenu) GUICtrlSetState($g_idWordWrap, $GUI_CHECKED) Local $idZoomMenu = GUICtrlCreateMenu("&Zoom", $idViewMenu) Local $idZoomIn = GUICtrlCreateMenuItem('Zoom &In' & @TAB & "Ctrl + Plus", $idZoomMenu) Local $idZoomOut = GUICtrlCreateMenuItem('Zoom &Out' & @TAB & "Ctrl + Minus", $idZoomMenu) Local $idZoomRestore = GUICtrlCreateMenuItem('&Restore Default Zoom' & @TAB & "Ctrl + 0", $idZoomMenu) Local $idThemeChange = GUICtrlCreateMenuItem('Toggle &Theme', $idViewMenu) $g_hStatus = _GUICtrlStatusBar_Create($g_hGUI) ;Added $ES_WANTRETURN $g_idEdit = GUICtrlCreateEdit("", 0, 0, -1, -1, BitOR($ES_WANTRETURN, $ES_NOHIDESEL, $WS_VSCROLL)) $g_hEdit = GUICtrlGetHandle(-1) _GuiCtrlEdit_SetIsZoomable($g_idEdit) _ReplaceFont($g_hEdit, 0, $g_sSelFontFamily, $g_iBaseFontSize) ; Subclass Edit control $g_hSubclassCallback = DllCallbackRegister("_EditSubclassProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") _WinAPI_SetWindowSubclass($g_hEdit, DllCallbackGetPtr($g_hSubclassCallback), 0) ; Set status bar parts Local $aParts[] = [1,1,1,1,1] ;Lazy, let size handler fix the real size. _GUICtrlStatusBar_SetParts($g_hStatus, -1, $aParts) _GUICtrlStatusBar_SetText($g_hStatus, "", 0) UpdateLineAndColumn() UpdateStatusBarEOL() _GUICtrlStatusBar_SetText($g_hStatus, "UTF-8", 4) RestoreZoom() ;also sets status bar value. If $__DM_g_bUseDarkMode Then _GUIDarkTheme_ApplyDark($g_hGUI) Else _GUIDarkTheme_ApplyLight($g_hGUI) EndIf ; This tells GUIDarkTheme UDF not to draw border around Edit control or show accent color when control has focus _GUIDarkTheme_CtrlBorderSet(False, False) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_DPICHANGED, "WM_DPICHANGED") GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idExit ExitLoop Case $idZoomIn _ZoomIn() Case $idZoomOut _ZoomOut() Case $idZoomRestore ;also using Ctrl+0 to restore zoom, so this has its own fn now RestoreZoom() Case $idThemeChange ;Redraw window in 1 go. _SendMessage($g_hGUI, $WM_SETREDRAW, False) _GUIDarkTheme_SwitchTheme($g_hGUI) _SendMessage($g_hGUI, $WM_SETREDRAW, True) _WinAPI_RedrawWindow($g_hGUI) Case $idOpen _OpenFile() Case $g_idWordWrap _WordWrap() EndSwitch WEnd GUIDelete() ; Clean up subclass before exiting ---- We're removing the subclass on WM_DESTROY, so we don't need to remove it here. DllCallbackFree($g_hSubclassCallback) EndFunc ;==>Notepad Func _WordWrap() ;Probably overkill.. Copy everything from previous ctrl. ; If we want to change pos later or something, we only need to update our code in 1 place. ;Position. Local $tWinRect = _WinAPI_GetWindowRect($g_hEdit) _WinAPI_MapWindowPoints(0, $g_hGUI, DllStructGetPtr($tWinRect), 2) ;convert coords, relative to parent. ;Styles. Local $iStyle = _WinAPI_GetWindowLong($g_hEdit, $GWL_STYLE) $iStyle = BitXOR($iStyle, $WS_HSCROLL) ;Flip $WS_HSCROLL bit Local $iWinExStyle = _WinAPI_GetWindowLong($g_hEdit, $GWL_EXSTYLE) ;Copy Font. Local $hFont = _GUICtrlEdit_GetFont($g_hEdit) Local $tLogFont = DllStructCreate($tagLOGFONT) _WinAPI_GetObject($hFont, DllStructGetSize($tLogFont), DllStructGetPtr($tLogFont)) $hFont = _WinAPI_CreateFontIndirect($tLogFont) ;Copy Edit ext styles etc Local $iEdtExStyle = _SendMessage($g_hEdit, $EM_GETEXTENDEDSTYLE) Local $iZmNum, $iZmDen _GuiCtrlEdit_GetZoom($g_hEdit, $iZmNum, $iZmDen) Local $iEOL = _GuiCtrlEdit_GetEOL($g_hEdit) ;Text Local $sText = _GUICtrlEdit_GetText($g_hEdit) ;Created with CuiCtrlCreate, we should delete with GUICtrlDelete. (au3 may need to do an internal cleanup) GUICtrlDelete($g_idEdit) $g_idEdit = GUICtrlCreateEdit($sText, $tWinRect.Left, $tWinRect.Top, _ ($tWinRect.Right - $tWinRect.Left), ($tWinRect.Bottom - $tWinRect.Top), _ $iStyle, $iWinExStyle) $g_hEdit = GUICtrlGetHandle(-1) _WinAPI_SetWindowSubclass($g_hEdit, DllCallbackGetPtr($g_hSubclassCallback), 0) _GUICtrlEdit_SetFont($g_hEdit, $hFont, False) _SendMessage($g_hEdit, $EM_SETEXTENDEDSTYLE, $iEdtExStyle, $iEdtExStyle) _GuiCtrlEdit_SetZoom($g_hEdit, $iZmNum, $iZmDen) _GuiCtrlEdit_SetEOL($g_hEdit, $iEOL) Local $bEnableDarkTheme = $__DM_g_bUseDarkMode _GUIDarkTheme_GUICtrlSetDarkTheme($g_hGUI, $g_hEdit, $bEnableDarkTheme) ;Give feedback. $iStyle = _WinAPI_GetWindowLong($g_hEdit, $GWL_STYLE) GUICtrlSetState($g_idWordWrap, BitAND($iStyle, $WS_HSCROLL) ? $GUI_CHECKED : $GUI_UNCHECKED) EndFunc ;==>_WordWrap Func _OpenFile() Local Const $sMessage = "Select a text file." ; Display an open dialog to select a list of file(s). Local $sFileOpenDialog = FileOpenDialog($sMessage, @DesktopDir, "All (*.*)|Text files (*.txt)", $FD_FILEMUSTEXIST) If @error Then ; Display the error message. MsgBox($MB_SYSTEMMODAL, "", "No file(s) were selected.") Else GUICtrlSetData($g_idEdit, "") GUICtrlSetData($g_idEdit, FileRead($sFileOpenDialog)) DetectEOL() EndIf EndFunc ;==>_OpenFile Func _ZoomIn() Local $iNum, $iDen _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) ;converts to correct values even if orig denominator <> 10 ;(a bit redundant as denominator shouldn't change from 10) $iNum = Int(10*($iNum / $iDen)) + 1 $iDen = Int(10*($iDen / $iDen)) _GuiCtrlEdit_SetZoom($g_idEdit, $iNum + 1, $iDen) UpdateStatusBarZoom() EndFunc ;==>_ZoomIn Func _ZoomOut() Local $iNum, $iDen _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) $iNum = 10*($iNum / $iDen) - 1 $iDen = 10*($iDen / $iDen) _GuiCtrlEdit_SetZoom($g_idEdit, $iNum, $iDen) UpdateStatusBarZoom() EndFunc ;==>_ZoomOut Func WM_DPICHANGED($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam _ReplaceFont($g_hEdit, _WinAPI_LoWord($wParam), $g_sSelFontFamily, $g_iBaseFontSize) Local $tRect = DllStructCreate($tagRECT, $lParam) _WinAPI_SetWindowPos($hWnd, 0, $tRect.Left, $tRect.Top, ($tRect.Right - $tRect.Left), ($tRect.Bottom - $tRect.Top), BitOR($SWP_NOACTIVATE, $SWP_NOZORDER)) EndFunc Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then Local $aSBarWidths[] = [0, 140, 50, 120, 120] _ScaleVals($aSBarWidths, $hWnd) Local $iW = _WinAPI_LoWord($lParam) Local $iH = _WinAPI_HiWord($lParam) $aSBarWidths[0] = $iW For $i = 1 To 4 $aSBarWidths[0] -= $aSBarWidths[$i] Next _GUICtrlStatusBar_SetParts($g_hStatus, -1, $aSBarWidths) _GUICtrlStatusBar_Resize($g_hStatus) ;Override Au3 Docking behavior, so we can deal with dpi changes _WinAPI_MoveWindow($g_hEdit, 0, 0, $iW, $iH - _WinAPI_GetWindowHeight($g_hStatus)) Return _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_WM_SIZE Func UpdateLineAndColumn() ;TODO: Need to fix - line nums are increasing with word wrap. ; Line count should be based entirely on EOL char/s. Local $aSel = _GUICtrlEdit_GetSel($g_hEdit) Local $iCharPos = $aSel[0] ; $aSel[0] is the starting character index Local $iLine = _GUICtrlEdit_LineFromChar($g_hEdit, $iCharPos) Local $iLineStartIndex = _GUICtrlEdit_LineIndex($g_hEdit, $iLine) Local $iCol = $iCharPos - $iLineStartIndex _GUICtrlStatusBar_SetText($g_hStatus, "Ln " & ($iLine + 1) & ", Col " & ($iCol + 1), 1) EndFunc ;==>UpdateLineAndColumn Func UpdateStatusBarZoom() Local $iNum, $iDen If _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) Then _GUICtrlStatusBar_SetText($g_hStatus, StringFormat("%d%%", 100 * ($iNum / $iDen)), 2) EndIf EndFunc ;==>UpdateStatusBarZoom Func DetectEOL() _GuiCtrlEdit_SetEOL($g_hEdit, $EC_ENDOFLINE_DETECTFROMCONTENT) UpdateStatusBarEOL() EndFunc Func UpdateStatusBarEOL() Local $sEOL Switch _GuiCtrlEdit_GetEOL($g_hEdit) Case 0, $EC_ENDOFLINE_CRLF $sEOL = "Windows (CRLF)" Case $EC_ENDOFLINE_CR $sEOL = "Macintosh (CR)" Case $EC_ENDOFLINE_LF $sEOL = "Unix (LF)" EndSwitch If $sEOL Then _GUICtrlStatusBar_SetText($g_hStatus, $sEOL, 3) EndIf EndFunc Func RestoreZoom() _GuiCtrlEdit_SetZoom($g_idEdit, 10, 10) UpdateStatusBarZoom() EndFunc ;==>RestoreZoom Func _EditSubclassProc($hWnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData) Switch $uMsg Case $WM_MOUSEWHEEL ;If Ctrl + Wheel, update zoom in status bar.. If BitAND(_WinAPI_LoWord($wParam), $MK_CONTROL) Then ;Update zoom BEFORE getting new size. Local $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam) UpdateStatusBarZoom() Return $iRet EndIf Case $WM_LBUTTONUP UpdateLineAndColumn() Case $WM_KEYUP UpdateLineAndColumn() Case $WM_DESTROY _WinAPI_DeleteObject(_GUICtrlEdit_GetFont($g_hEdit)) ;Same as what you had, but we may as well use the wrapped func. _WinAPI_RemoveWindowSubclass($hWnd, DllCallbackGetPtr($g_hSubclassCallback), $uIdSubclass) EndSwitch ; Pass message down to the default subclass handler chain Return _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam) EndFunc ;==>_EditSubclassProc Func _WinAPI_MapWindowPoints($hWndFom, $hWndTo, $pPoints, $iCount) Local $aCall = DllCall("User32.dll", "int", "MapWindowPoints", "hwnd", $hWndFom, "hwnd", $hWndTo, "ptr", $pPoints, "int", $iCount) If @error Then Return SetError(@error, @extended, $aCall) Return $aCall[0] EndFunc ;==>_WinAPI_MapWindowPoints Func _WinAPI_GetDpiForSystem() Local $aCall = DllCall("User32.dll", "uint", "GetDpiForSystem") If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc Func _WinAPI_GetDpiForWindow($hWnd) Local $aCall = DllCall("User32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd) If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc Func _ScaleVals(ByRef $aValues, $hWnd = 0) Local $iDPI = _WinAPI_IsWindow($hWnd) ? _WinAPI_GetDpiForWindow($hWnd) : _WinAPI_GetDpiForSystem() If @error Then $iDPI = 96 For $i = 0 To UBound($aValues)- 1 $aValues[$i] = _WinAPI_MulDiv($aValues[$i], $iDPI, 96) Next EndFunc Func _ReplaceFont($hWnd, $iDPI, $sTypefaceName, $iSize, $iWeight = $FW_NORMAL, $bItalic = False, $bUnderline = False, $bStrikeOut = False) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If $iDPI < 1 Then $iDPI = _WinAPI_IsWindow($hWnd) ? _WinAPI_GetDpiForWindow($hWnd) : _WinAPI_GetDpiForSystem() If @error Then $iDPI = 96 EndIf Local $iHeight = - _WinAPI_MulDiv($iSize, $iDPI, 72) Local $hOldFont = _SendMessage($hWnd, $WM_GETFONT) Local $hNewFont = _WinAPI_CreateFont($iHeight, 0, 0, 0, $iWeight, $bItalic, $bUnderline, $bStrikeOut, _ $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, BitOR($DEFAULT_PITCH, $FF_DONTCARE), $sTypefaceName) _SendMessage($hWnd, $WM_SETFONT, $hNewFont, 1) If $hOldFont Then _WinAPI_DeleteObject($hOldFont) Return $hNewFont EndFunc Func _GUICtrlEdit_SetFont($hWnd, $hFont, $bRedraw = True) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If _WinAPI_IsClassName($hWnd, $WC_EDIT) Then Return _SendMessage($hWnd, $WM_SETFONT, $hFont, $bRedraw) EndFunc Func _GUICtrlEdit_GetFont($hWnd) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If _WinAPI_IsClassName($hWnd, $WC_EDIT) Then Return _SendMessage($hWnd, $WM_GETFONT, 0, 0, 0, "wparam", "lparam", "handle") EndFunc WildByDesign 1
WildByDesign Posted September 25 Author Posted September 25 6 hours ago, MattyD said: Hope you don't mind, but I've added a few bits and bobs for fun. (take or leave it ) Thank you so much for this well organized contribution. I will certainly accept all of it and update the first post with it, but I just want to clarify some things. But first, I just wanted to mention that I really like the way that you've organized the code and the code comments and such. It has inspired me to continue doing some more work on this Notepad clone. I already know much of what I need to do (and how to do it), I'm just lacking time lately to implement some of what I want to do. Case $idThemeChange ;Redraw window in 1 go. _SendMessage($g_hGUI, $WM_SETREDRAW, False) _GUIDarkTheme_SwitchTheme($g_hGUI) _SendMessage($g_hGUI, $WM_SETREDRAW, True) _WinAPI_RedrawWindow($g_hGUI) I like your usage of WM_SETREDRAW here. The only problem that I have noticed is that WM_SETREDRAW seems to prevent the painting of the 1 pixel white line below the menu bar in dark mode. As a temporary fix, this seems to correct it and the Sleep(10) seems to be really needed: Case $idThemeChange ;Redraw window in 1 go. _SendMessage($g_hGUI, $WM_SETREDRAW, False) _GUIDarkTheme_SwitchTheme($g_hGUI) _SendMessage($g_hGUI, $WM_SETREDRAW, True) _WinAPI_RedrawWindow($g_hGUI) Sleep(10) If $__DM_g_bUseDarkMode Then __GUIDarkMenu_PaintWhiteLine($g_hGUI) This reminds me, I have been curious about learning more about (and using) _WinAPI_PostMessage with a custom window message and handler. I've thought about this recently with WM_DPICHANGED because there are a couple of controls that prefer a delayed measurement due to internal caching of text sizes. That way, I assume, it would run the custom message handler when the OS is completely finished with the current message. That may be beneficial to this WM_SETREDRAW situation as well where the painting of the white line seems to need a slight delay. I should also mention, my _GUIDarkTheme_SwitchTheme() function is also using _WinAPI_LockWindowUpdate() in its helper function __DM_ThemeCleanupHelper(). The helper function gets called twice in _GUIDarkTheme_SwitchTheme() for the two different cases representing stages. From my understanding, using _WinAPI_LockWindowUpdate() is not the best method. But it does not seem to affect the painting of the white line. Your WM_SETREDRAW method seems to be the method that is recommended by MS and is therefore better to use. Should I get rid of my usage of _WinAPI_LockWindowUpdate?
WildByDesign Posted September 25 Author Posted September 25 (edited) I'm using the @MattyD version as a base for this Notepad script now since it is structured much better. I've added updating the text encoding to the statusbar part whenever a file is opened. Func _OpenFile() Local Const $sMessage = "Select a text file." ; Display an open dialog to select a list of file(s). Local $sFileOpenDialog = FileOpenDialog($sMessage, @DesktopDir, "All (*.*)|Text files (*.txt)", $FD_FILEMUSTEXIST) If @error Then ; Display the error message. MsgBox($MB_SYSTEMMODAL, "", "No file(s) were selected.") Else GUICtrlSetData($g_idEdit, "") GUICtrlSetData($g_idEdit, FileRead($sFileOpenDialog)) DetectEOL() UpdateStatusBarEncoding($sFileOpenDialog) ; <<< added EndIf EndFunc ;==>_OpenFile Func UpdateStatusBarEncoding($sFile) Local $sText Local $iEncoding = FileGetEncoding($sFile, $FE_PARTIALFIRST_UTF8) Switch $iEncoding Case $FO_UTF16_LE $sText = 'UTF-16 Little Endian' Case $FO_UTF16_BE $sText = 'UTF-16 Big Endian' Case $FO_UTF8 $sText = 'UTF-8 (with BOM)' Case $FO_UTF8_NOBOM $sText = 'UTF-8 (without BOM)' Case $FO_ANSI $sText = 'ANSI' EndSwitch _GUICtrlStatusBar_SetText($g_hStatus, $sText, 4) EndFunc ;==>UpdateStatusBarEncoding It might even be interesting to be able to change the text encoding as well. We could add that to the menu but I think there are much more higher priority things that need to be added first. Edited September 25 by WildByDesign MattyD 1
MattyD Posted September 26 Posted September 26 3 hours ago, WildByDesign said: I will certainly accept all of it and update the first post with it You should pick through it though, I was moving pretty quickly so there's probably errors.. This line in particular is dumb, 10*1 is always 10! $iDen = Int(10*($iDen / $iDen)) 3 hours ago, WildByDesign said: If $__DM_g_bUseDarkMode Then __GUIDarkMenu_PaintWhiteLine($g_hGUI) Ah ok, If you draw the line during the windows paint cycle you shouldn't have to draw it everywhere ad hoc... In your main window's subclass, handling $WM_NCPAINT would probably do it. Call DefSubclass first, then paint your line. 3 hours ago, WildByDesign said: That way, I assume, it would run the custom message handler when the OS is completely finished with the current message Yep exactly. SendMessage bypasses the queue, its synchronous - the message is processed and returned immediately. Postmessage adds the msg to the queue to be processed later. Because the queue dispatches messages one at a time, any message you post within a handler cannot be executed until after you return. 3 hours ago, WildByDesign said: Should I get rid of my usage of _WinAPI_LockWindowUpdate? Yeah probably. You can only lock one window at a time, so there's that caveat too. The documentation says: The purpose of the LockWindowUpdate function is to permit drag/drop feedback to be drawn over a window without interference from the window itself. The intent is that the window is locked when feedback is drawn and unlocked when feedback is complete. LockWindowUpdate is not intended for general-purpose suppression of window redraw. Use the WM_SETREDRAW message to disable redrawing of a particular window. WildByDesign 1
WildByDesign Posted September 26 Author Posted September 26 10 hours ago, MattyD said: You should pick through it though, I was moving pretty quickly so there's probably errors.. This line in particular is dumb, 10*1 is always 10! One thing that I can't quite understand is that Zoom In goes up 20% each click, while Zoom Out goes down 10% at a time. I would like to match Notepad at 10% zoom in/out. I can't really figure out by looking at the code in _ZoomIn() and _ZoomOut() functions where that 20% is coming from,
MattyD Posted September 26 Posted September 26 Just another silly error! ;original Func _ZoomIn() Local $iNum, $iDen _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) ;converts to correct values even if orig denominator <> 10 ;(maybe a bit OTT as den shouldn't really chage from 10) $iNum = Int(10*($iNum / $iDen)) + 1 ;incrementing here. $iDen = Int(10*($iDen / $iDen)) _GuiCtrlEdit_SetZoom($g_idEdit, $iNum + 1, $iDen) ;also incrementing here. UpdateStatusBarZoom() EndFunc ;a bit better... Func _ZoomIn() Local $iNum, $iDen _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) $iNum = Round(10*($iNum / $iDen)) + 1 _GuiCtrlEdit_SetZoom($g_idEdit, $iNum, 10) UpdateStatusBarZoom() EndFunc WildByDesign 1
WildByDesign Posted September 28 Author Posted September 28 I've updated the source archive in the first post. Notepad 2026-09-28: Using @MattyD's structural changes and improvements as a base script Added UpdateStatusBarEncoding function to updating text encoding on status bar Added Status Bar to View menu to show/hide status bar Added _StatusChange function to handle everything needed to showing/hiding status bar Sends WM_SIZE message to trigger Edit control sizing changes immediately Updated WM_SIZE handler function to account for hidden Edit control sizing As always, if anyone wants to contribute and add some bits and pieces, please feel free. That is always welcome. If we do end up with multiple people working on this, maybe we can leave a comment such as "I am going to work on such and such feature". That way we don't end up with two people working on the same thing. Anyway, that is just a suggestion.
WildByDesign Posted September 28 Author Posted September 28 I just wanted to give a quick heads up that I am working on text change modification tracking right now. Specifically, I am adding a WM_COMMAND handler to check the file anytime a change has been made to the text that is currently in the Edit control. If a change has been made, it adds the asterisk to the title bar to indicate that there are changes needed to be saved. If the change gets reverted to the original text, the asterisk is removed. I also added the currently opened file name to the title bar. Somehow it's already better than MS implementation because they don't remove the asterisk when you revert the change. So our change tracking will be better in that regard.
WildByDesign Posted September 28 Author Posted September 28 Notepad 2026-09-28b: Added change indicator to title bar when save changes are pending Added Save and Save As to File menu I still need to add a warning or save as dialog for when a user tries to close the app when there are pending save changes. Same needs to be done if there are pending changes to save and a user goes to Open a new file. If anyone has the time and wants to check over my _SaveFile() and _SaveFileAs() functions that would be great. I tested it quite a bit but there are always scenarios that I don't think of and I tried to rush as much as I could today. argumentum 1
argumentum Posted September 28 Posted September 28 (edited) ... Func _SaveFileAs_NextName($sInitFolder) Local $iNext = 0, $sExt = '.txt', $sName = 'textFile' Local $sPath = _WinAPI_ShellGetKnownFolderPath($sInitFolder) If @error Or $sPath = "" Then $sPath = @DesktopDir If Not FileExists($sPath & '\' & $sName & $sExt) Then Return $sName & $sExt Do $iNext += 1 If Not FileExists($sPath & '\' & $sName & ' (' & $iNext & ')' & $sExt) Then Return $sName & ' (' & $iNext & ')' & $sExt Until 0 EndFunc ;==>_SaveFileAs_NextName Func _SaveFileAs() Local $sFileSaveDialog, $hFile, $sDrive = "", $sDir = "", $sFileName = "", $sExtension = "" If Not $g_sOpenFile Then $sFileName = _SaveFileAs_NextName("::{450D8FBA-AD25-11D0-98A8-0800361B1103}") $sFileSaveDialog = FileSaveDialog("Save As", "::{450D8FBA-AD25-11D0-98A8-0800361B1103}", "Text Documents (*.txt)|All (*.*)", $FD_PATHMUSTEXIST + $FD_PROMPTOVERWRITE, $sFileName) If Not @error Then ... ..also, there is a " - Notepad". About "Notapad" Edit: "Nota" is Spanish ( or latin, or italian ) for note Edit 2: The Germanic for note is notu. So if the play in words are not welcome ( lack of humor ) then maybe the other 🤔 Edited September 28 by argumentum clarify WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
MattyD Posted September 29 Posted September 29 I wasted some time doing a fancy "about box" today, but it does require the new dialogs UDF that's just been uploaded. Change the text to whatever you like, its just sample text. and it still needs dark-mode-ifying. expandcollapse popup#NoTrayIcon #AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <BorderConstants.au3> #include <FileConstants.au3> #include <FontConstants.au3> #include <MsgBoxConstants.au3> #include <WinAPIGdi.au3> #include <WindowsStylesConstants.au3> #include <GUIConstantsEx.au3> #include <EditConstants.au3> #include <GuiStatusBar.au3> #include <WindowsConstants.au3> #include <File.au3> #include "GUIDarkTheme.au3" #include "GuiEditEx.au3" #include "Dialogs.au3" Global $__g_NotepadVer = "2026.09.28b" ;Virtual key - the definition probably exists in a standard include library somewhere, but I'm too lazy to find it atm. ;Used to monitor control-wheel zooming. Global Const $MK_CONTROL = 0x0008 ; DPI awareness - nit-picky, but no magic numbers! DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ;~ Global Const $DWLP_MSGRESULT = 0 ;Currently required - will be included into Dialogs UDF for the next release.. Global $g_hAboutDlgProc = DllCallbackRegister("AboutDlgProc", "int_ptr", "hwnd;uint;wparam;lparam") ;Or technically this is a bit better because the DPI_AWARENESS_CONTEXT type is a pseudo-handle - not a signed int. ;~ Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = Ptr(-4) ;~ DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "handle", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ;{+} is the key on the top row, which you need "shift" to get to. ;So we should use "=" for zooming in here, or {NUMPADADD} for the other "plus" key. HotKeySet("^=", "_ZoomIn") HotKeySet("^{NUMPADADD}", "_ZoomIn") HotKeySet("^-", "_ZoomOut") HotKeySet("^{NUMPADSUB}", "_ZoomOut") HotKeySet("^0", "RestoreZoom") Global $g_iBaseFontSize = 11, $g_sSelFontFamily = "Consolas" Global $g_hGUI, $g_idEdit, $g_hEdit, $g_hStatus, $g_idWordWrap, $g_sText = "", $g_sOpenFile = 0 Global $g_sFileName = "Untitled" Global $g_hSubclassCallback = 0 Global $idFileMenu, $idSave, $idSaveAs Notepad() Func Notepad() _Dialog_Startup() Local $hAboutBoxTemplate = _Dialog_NewTemplate("About Dialog", 160, 80, -1, -1, BitOR($WS_CLIPCHILDREN, $WS_BORDER, $WS_POPUP, $WS_SYSMENU, $DS_SETFONT), 0) _Dialog_SetFont($hAboutBoxTemplate, "Segoe UI Symbol", 10) _Dialog_AddButton($hAboutBoxTemplate, $IDCLOSE, "", 160-15, 5, 10, 10, BitOR($BS_OWNERDRAW, $BS_DEFPUSHBUTTON)) Local $aWinDims[2] = [760, 500] _ScaleVals($aWinDims) $g_hGUI = GUICreate($g_sFileName & " - Notepad", $aWinDims[0], $aWinDims[1], -1, -1, $WS_OVERLAPPEDWINDOW) $idFileMenu = GUICtrlCreateMenu("&File") Local $idOpen = GUICtrlCreateMenuItem("&Open...", $idFileMenu) $idSave = GUICtrlCreateMenuItem("&Save", $idFileMenu) GUICtrlSetState($idSave, $GUI_DISABLE) $idSaveAs = GUICtrlCreateMenuItem("Save &As...", $idFileMenu) GUICtrlCreateMenuItem("", $idFileMenu) Local $idExit = GUICtrlCreateMenuItem("E&xit", $idFileMenu) Local $idEditMenu = GUICtrlCreateMenu("&Edit") Local $idFormatMenu = GUICtrlCreateMenu("&Format") Local $idViewMenu = GUICtrlCreateMenu("&View") Local $idHelpMenu = GUICtrlCreateMenu("&Help") $g_idWordWrap = GUICtrlCreateMenuItem('Word &Wrap', $idFormatMenu) GUICtrlSetState($g_idWordWrap, $GUI_CHECKED) Local $idThemeChange = GUICtrlCreateMenuItem('Toggle &Theme', $idViewMenu) Local $idZoomMenu = GUICtrlCreateMenu("&Zoom", $idViewMenu) Local $idZoomIn = GUICtrlCreateMenuItem('Zoom &In' & @TAB & "Ctrl + Plus", $idZoomMenu) Local $idZoomOut = GUICtrlCreateMenuItem('Zoom &Out' & @TAB & "Ctrl + Minus", $idZoomMenu) Local $idZoomRestore = GUICtrlCreateMenuItem('&Restore Default Zoom' & @TAB & "Ctrl + 0", $idZoomMenu) Local $idStatusShow = GUICtrlCreateMenuItem("Status Bar", $idViewMenu) Local $idAbout = GUICtrlCreateMenuItem("&About", $idHelpMenu) Local $idCut = GUICtrlCreateMenuItem('Cu&t' & @TAB & "Ctrl + X", $idEditMenu) Local $idCopy = GUICtrlCreateMenuItem('&Copy' & @TAB & "Ctrl + C", $idEditMenu) Local $idPaste = GUICtrlCreateMenuItem('&Paste ' & @TAB & "Ctrl + V", $idEditMenu) GUICtrlSetState($idStatusShow, $GUI_CHECKED) $g_hStatus = _GUICtrlStatusBar_Create($g_hGUI) ;Added $ES_WANTRETURN $g_idEdit = GUICtrlCreateEdit("", 0, 0, -1, -1, BitOR($ES_WANTRETURN, $ES_NOHIDESEL, $WS_VSCROLL)) $g_hEdit = GUICtrlGetHandle(-1) _GuiCtrlEdit_SetIsZoomable($g_idEdit) _ReplaceFont($g_hEdit, 0, $g_sSelFontFamily, $g_iBaseFontSize) ; Subclass Edit control $g_hSubclassCallback = DllCallbackRegister("_EditSubclassProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") _WinAPI_SetWindowSubclass($g_hEdit, DllCallbackGetPtr($g_hSubclassCallback), 0) ; Set status bar parts Local $aParts[] = [1,1,1,1,1] ;Lazy, let size handler fix the real size. _GUICtrlStatusBar_SetParts($g_hStatus, -1, $aParts) _GUICtrlStatusBar_SetText($g_hStatus, "", 0) UpdateLineAndColumn() UpdateStatusBarEOL() _GUICtrlStatusBar_SetText($g_hStatus, "UTF-8", 4) RestoreZoom() ;also sets status bar value. If $__DM_g_bUseDarkMode Then _GUIDarkTheme_ApplyDark($g_hGUI) Else _GUIDarkTheme_ApplyLight($g_hGUI) EndIf ; This tells GUIDarkTheme UDF not to draw border around Edit control or show accent color when control has focus _GUIDarkTheme_CtrlBorderSet(False, False) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUIRegisterMsg($WM_DPICHANGED, "WM_DPICHANGED") GUISetState() While 1 Switch GUIGetMsg() Case $idAbout _Dialog_LaunchModal($hAboutBoxTemplate, $g_hGUI, 0, $g_hAboutDlgProc) Case $GUI_EVENT_CLOSE, $idExit ExitLoop Case $idZoomIn _ZoomIn() Case $idZoomOut _ZoomOut() Case $idZoomRestore ;also using Ctrl+0 to restore zoom, so this has its own fn now RestoreZoom() Case $idThemeChange _GUIDarkTheme_SwitchTheme($g_hGUI) Case $idOpen _OpenFile() Case $g_idWordWrap _WordWrap() Case $idStatusShow _StatusChange($idStatusShow) Case $idSave _SaveFile() Case $idSaveAs _SaveFileAs() Case $idCut _GuiCtrlEdit_Cut($g_hEdit) Case $idCopy _GuiCtrlEdit_Copy($g_hEdit) Case $idPaste _GuiCtrlEdit_Paste($g_hEdit) EndSwitch WEnd GUIDelete() _Dialog_Shutdown() ; Clean up subclass before exiting ---- We're removing the subclass on WM_DESTROY, so we don't need to remove it here. DllCallbackFree($g_hSubclassCallback) EndFunc ;==>Notepad Func _WordWrap() ;Probably overkill.. Copy everything from previous ctrl. ; If we want to change pos later or something, we only need to update our code in 1 place. ;Position. Local $tWinRect = _WinAPI_GetWindowRect($g_hEdit) _WinAPI_MapWindowPoints(0, $g_hGUI, DllStructGetPtr($tWinRect), 2) ;convert coords, relative to parent. ;Styles. Local $iStyle = _WinAPI_GetWindowLong($g_hEdit, $GWL_STYLE) $iStyle = BitXOR($iStyle, $WS_HSCROLL) ;Flip $WS_HSCROLL bit Local $iWinExStyle = _WinAPI_GetWindowLong($g_hEdit, $GWL_EXSTYLE) ;Copy Font. Local $hFont = _GUICtrlEdit_GetFont($g_hEdit) Local $tLogFont = DllStructCreate($tagLOGFONT) _WinAPI_GetObject($hFont, DllStructGetSize($tLogFont), DllStructGetPtr($tLogFont)) $hFont = _WinAPI_CreateFontIndirect($tLogFont) ;Copy Edit ext styles etc Local $iEdtExStyle = _SendMessage($g_hEdit, $EM_GETEXTENDEDSTYLE) Local $iZmNum, $iZmDen _GuiCtrlEdit_GetZoom($g_hEdit, $iZmNum, $iZmDen) Local $iEOL = _GuiCtrlEdit_GetEOL($g_hEdit) ;Text Local $sText = _GUICtrlEdit_GetText($g_hEdit) ;Created with CuiCtrlCreate, we should delete with GUICtrlDelete. (au3 may need to do an internal cleanup) GUICtrlDelete($g_idEdit) $g_idEdit = GUICtrlCreateEdit($sText, $tWinRect.Left, $tWinRect.Top, _ ($tWinRect.Right - $tWinRect.Left), ($tWinRect.Bottom - $tWinRect.Top), _ $iStyle, $iWinExStyle) $g_hEdit = GUICtrlGetHandle(-1) _WinAPI_SetWindowSubclass($g_hEdit, DllCallbackGetPtr($g_hSubclassCallback), 0) _GUICtrlEdit_SetFont($g_hEdit, $hFont, False) _SendMessage($g_hEdit, $EM_SETEXTENDEDSTYLE, $iEdtExStyle, $iEdtExStyle) _GuiCtrlEdit_SetZoom($g_hEdit, $iZmNum, $iZmDen) _GuiCtrlEdit_SetEOL($g_hEdit, $iEOL) Local $bEnableDarkTheme = $__DM_g_bUseDarkMode _GUIDarkTheme_GUICtrlSetDarkTheme($g_hGUI, $g_hEdit, $bEnableDarkTheme) ;Give feedback. $iStyle = _WinAPI_GetWindowLong($g_hEdit, $GWL_STYLE) GUICtrlSetState($g_idWordWrap, BitAND($iStyle, $WS_HSCROLL) ? $GUI_CHECKED : $GUI_UNCHECKED) EndFunc ;==>_WordWrap Func UpdateStatusBarEncoding($sFile) Local $sText Local $iEncoding = FileGetEncoding($sFile, $FE_PARTIALFIRST_UTF8) Switch $iEncoding Case $FO_UTF16_LE $sText = 'UTF-16 Little Endian' Case $FO_UTF16_BE $sText = 'UTF-16 Big Endian' Case $FO_UTF8 $sText = 'UTF-8 (with BOM)' Case $FO_UTF8_NOBOM $sText = 'UTF-8 (without BOM)' Case $FO_ANSI $sText = 'ANSI' EndSwitch _GUICtrlStatusBar_SetText($g_hStatus, $sText, 4) EndFunc ;==>UpdateStatusBarEncoding Func _ZoomIn() Local $iNum, $iDen _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) $iNum = Round(10*($iNum / $iDen)) + 1 _GuiCtrlEdit_SetZoom($g_idEdit, $iNum, 10) UpdateStatusBarZoom() EndFunc ;==>_ZoomIn Func _ZoomOut() Local $iNum, $iDen _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) $iNum = 10*($iNum / $iDen) - 1 $iDen = 10*($iDen / $iDen) _GuiCtrlEdit_SetZoom($g_idEdit, $iNum, $iDen) UpdateStatusBarZoom() EndFunc ;==>_ZoomOut Func WM_DPICHANGED($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam _ReplaceFont($g_hEdit, _WinAPI_LoWord($wParam), $g_sSelFontFamily, $g_iBaseFontSize) Local $tRect = DllStructCreate($tagRECT, $lParam) _WinAPI_SetWindowPos($hWnd, 0, $tRect.Left, $tRect.Top, ($tRect.Right - $tRect.Left), ($tRect.Bottom - $tRect.Top), BitOR($SWP_NOACTIVATE, $SWP_NOZORDER)) EndFunc Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then Local $aSBarWidths[] = [0, 140, 50, 120, 140] _ScaleVals($aSBarWidths, $hWnd) Local $iW = _WinAPI_LoWord($lParam) Local $iH = _WinAPI_HiWord($lParam) $aSBarWidths[0] = $iW For $i = 1 To 4 $aSBarWidths[0] -= $aSBarWidths[$i] Next _GUICtrlStatusBar_SetParts($g_hStatus, -1, $aSBarWidths) _GUICtrlStatusBar_Resize($g_hStatus) ;Override Au3 Docking behavior, so we can deal with dpi changes Local $bStatusShow = _WinAPI_IsWindowVisible($g_hStatus) _WinAPI_MoveWindow($g_hEdit, 0, 0, $iW, $iH - ($bStatusShow ? _WinAPI_GetWindowHeight($g_hStatus) : 0)) Return _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_WM_SIZE Func UpdateLineAndColumn() ;TODO: Need to fix - line nums are increasing with word wrap. ; Line count should be based entirely on EOL char/s. Local $aSel = _GUICtrlEdit_GetSel($g_hEdit) Local $iCharPos = $aSel[0] ; $aSel[0] is the starting character index Local $iLine = _GUICtrlEdit_LineFromChar($g_hEdit, $iCharPos) Local $iLineStartIndex = _GUICtrlEdit_LineIndex($g_hEdit, $iLine) Local $iCol = $iCharPos - $iLineStartIndex _GUICtrlStatusBar_SetText($g_hStatus, "Ln " & ($iLine + 1) & ", Col " & ($iCol + 1), 1) EndFunc ;==>UpdateLineAndColumn Func UpdateStatusBarZoom() Local $iNum, $iDen If _GUICtrlEdit_GetZoom($g_hEdit, $iNum, $iDen) Then _GUICtrlStatusBar_SetText($g_hStatus, StringFormat("%d%%", 100 * ($iNum / $iDen)), 2) EndIf EndFunc ;==>UpdateStatusBarZoom Func DetectEOL() _GuiCtrlEdit_SetEOL($g_hEdit, $EC_ENDOFLINE_DETECTFROMCONTENT) UpdateStatusBarEOL() EndFunc Func UpdateStatusBarEOL() Local $sEOL Switch _GuiCtrlEdit_GetEOL($g_hEdit) Case 0, $EC_ENDOFLINE_CRLF $sEOL = "Windows (CRLF)" Case $EC_ENDOFLINE_CR $sEOL = "Macintosh (CR)" Case $EC_ENDOFLINE_LF $sEOL = "Unix (LF)" EndSwitch If $sEOL Then _GUICtrlStatusBar_SetText($g_hStatus, $sEOL, 3) EndIf EndFunc Func RestoreZoom() _GuiCtrlEdit_SetZoom($g_idEdit, 10, 10) UpdateStatusBarZoom() EndFunc ;==>RestoreZoom Func _EditSubclassProc($hWnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData) #forceref $dwRefData Switch $uMsg Case $WM_MOUSEWHEEL ;If Ctrl + Wheel, update zoom in status bar.. If BitAND(_WinAPI_LoWord($wParam), $MK_CONTROL) Then ;Update zoom BEFORE getting new size. Local $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam) UpdateStatusBarZoom() Return $iRet EndIf Case $WM_LBUTTONUP UpdateLineAndColumn() Case $WM_KEYUP UpdateLineAndColumn() Case $WM_DESTROY _WinAPI_DeleteObject(_GUICtrlEdit_GetFont($g_hEdit)) ;Same as what you had, but we may as well use the wrapped func. _WinAPI_RemoveWindowSubclass($hWnd, DllCallbackGetPtr($g_hSubclassCallback), $uIdSubclass) EndSwitch ; Pass message down to the default subclass handler chain Return _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam) EndFunc ;==>_EditSubclassProc Func _WinAPI_MapWindowPoints($hWndFom, $hWndTo, $pPoints, $iCount) Local $aCall = DllCall("User32.dll", "int", "MapWindowPoints", "hwnd", $hWndFom, "hwnd", $hWndTo, "ptr", $pPoints, "int", $iCount) If @error Then Return SetError(@error, @extended, $aCall) Return $aCall[0] EndFunc ;==>_WinAPI_MapWindowPoints Func _WinAPI_GetDpiForSystem() Local $aCall = DllCall("User32.dll", "uint", "GetDpiForSystem") If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc Func _WinAPI_GetDpiForWindow($hWnd) Local $aCall = DllCall("User32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd) If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc Func _ScaleVals(ByRef $aValues, $hWnd = 0) Local $iDPI = _WinAPI_IsWindow($hWnd) ? _WinAPI_GetDpiForWindow($hWnd) : _WinAPI_GetDpiForSystem() If @error Then $iDPI = 96 For $i = 0 To UBound($aValues)- 1 $aValues[$i] = _WinAPI_MulDiv($aValues[$i], $iDPI, 96) Next EndFunc Func _StatusChange($idStatusShow) Local $bStatusShow If $g_hStatus Then $bStatusShow = _WinAPI_IsWindowVisible($g_hStatus) Switch $bStatusShow Case 1 _GUICtrlStatusBar_ShowHide($g_hStatus, @SW_HIDE) GUICtrlSetState($idStatusShow, $GUI_UNCHECKED) Case 0 _GUICtrlStatusBar_ShowHide($g_hStatus, @SW_SHOW) GUICtrlSetState($idStatusShow, $GUI_CHECKED) EndSwitch ; Get current client area width and height Local $aClientSize = WinGetClientSize($g_hGUI) Local $iWidth = $aClientSize[0] Local $iHeight = $aClientSize[1] ; Combine width and height into LPARAM using _WinAPI_MakeLong Local $lParam = _WinAPI_MakeLong($iWidth, $iHeight) ; Trigger WM_SIZE so that Edit box resizes to changed status bar _SendMessage($g_hGUI, $WM_SIZE, 0, $lParam) EndIf EndFunc Func _ReplaceFont($hWnd, $iDPI, $sTypefaceName, $iSize, $iWeight = $FW_NORMAL, $bItalic = False, $bUnderline = False, $bStrikeOut = False) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If $iDPI < 1 Then $iDPI = _WinAPI_IsWindow($hWnd) ? _WinAPI_GetDpiForWindow($hWnd) : _WinAPI_GetDpiForSystem() If @error Then $iDPI = 96 EndIf Local $iHeight = - _WinAPI_MulDiv($iSize, $iDPI, 72) Local $hOldFont = _SendMessage($hWnd, $WM_GETFONT) Local $hNewFont = _WinAPI_CreateFont($iHeight, 0, 0, 0, $iWeight, $bItalic, $bUnderline, $bStrikeOut, _ $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, BitOR($DEFAULT_PITCH, $FF_DONTCARE), $sTypefaceName) _SendMessage($hWnd, $WM_SETFONT, $hNewFont, 1) If $hOldFont Then _WinAPI_DeleteObject($hOldFont) Return $hNewFont EndFunc Func _GUICtrlEdit_SetFont($hWnd, $hFont, $bRedraw = True) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If _WinAPI_IsClassName($hWnd, $WC_EDIT) Then Return _SendMessage($hWnd, $WM_SETFONT, $hFont, $bRedraw) EndFunc Func _GUICtrlEdit_GetFont($hWnd) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) If _WinAPI_IsClassName($hWnd, $WC_EDIT) Then Return _SendMessage($hWnd, $WM_GETFONT, 0, 0, 0, "wparam", "lparam", "handle") EndFunc Func _Notepad_Version() Return $__g_NotepadVer EndFunc ;==>_Notepad_Version Func _OpenFile() Local Const $sMessage = "Select a text file." ; Display an open dialog to select a list of file(s). Local $sFileOpenDialog = FileOpenDialog($sMessage, @DesktopDir, "Text Documents (*.txt)|All (*.*)", $FD_FILEMUSTEXIST) If Not @error Then ; Clear previous text and Edit control $g_sText = "" GUICtrlSetData($g_idEdit, $g_sText) $g_sText = FileRead($sFileOpenDialog) $g_sOpenFile = $sFileOpenDialog GUICtrlSetData($g_idEdit, $g_sText) DetectEOL() UpdateStatusBarEncoding($sFileOpenDialog) Local $sDrive = "", $sDir = "", $sFileName = "", $sExtension = "" _PathSplit($sFileOpenDialog, $sDrive, $sDir, $sFileName, $sExtension) $g_sFileName = $sFileName & $sExtension WinSetTitle($g_hGUI, "", $g_sFileName & " - Notepad") EndIf EndFunc ;==>_OpenFile Func _SaveFile() Local $hFile If Not $g_sOpenFile Then Local $sFileSaveDialog = FileSaveDialog("Save As", "::{450D8FBA-AD25-11D0-98A8-0800361B1103}", "Text Documents (*.txt)|All (*.*)", $FD_PATHMUSTEXIST + $FD_PROMPTOVERWRITE, "*.txt") If Not @error Then $hFile = FileOpen($sFileSaveDialog, $FO_OVERWRITE + $FO_UTF8) FileWrite($hFile, GUICtrlRead($g_idEdit)) FileClose($hFile) $g_sOpenFile = $sFileSaveDialog Local $sDrive = "", $sDir = "", $sFileName = "", $sExtension = "" _PathSplit($sFileSaveDialog, $sDrive, $sDir, $sFileName, $sExtension) $g_sFileName = $sFileName & $sExtension WinSetTitle($g_hGUI, "", $g_sFileName & " - Notepad") GUICtrlSetState($idSave, $GUI_DISABLE) $g_sText = GUICtrlRead($g_idEdit) EndIf Else Local $iEncoding = FileGetEncoding($g_sOpenFile) If $iEncoding = -1 Then $iEncoding = 128 ;FileMove($g_sOpenFile, $g_sOpenFile & "." & TimerInit()) ; backup ? $hFile = FileOpen($g_sOpenFile, $FO_OVERWRITE + $iEncoding) FileWrite($hFile, GUICtrlRead($g_idEdit)) FileClose($hFile) WinSetTitle($g_hGUI, "", $g_sFileName & " - Notepad") GUICtrlSetState($idSave, $GUI_DISABLE) $g_sText = GUICtrlRead($g_idEdit) EndIf EndFunc ;==>_SaveFile Func _SaveFileAs() Local $sFileSaveDialog, $hFile, $sDrive = "", $sDir = "", $sFileName = "", $sExtension = "" If Not $g_sOpenFile Then $sFileSaveDialog = FileSaveDialog("Save As", "::{450D8FBA-AD25-11D0-98A8-0800361B1103}", "Text Documents (*.txt)|All (*.*)", $FD_PATHMUSTEXIST + $FD_PROMPTOVERWRITE, "*.txt") If Not @error Then $hFile = FileOpen($sFileSaveDialog, $FO_OVERWRITE + $FO_UTF8) FileWrite($hFile, GUICtrlRead($g_idEdit)) FileClose($hFile) $g_sOpenFile = $sFileSaveDialog _PathSplit($sFileSaveDialog, $sDrive, $sDir, $sFileName, $sExtension) $g_sFileName = $sFileName & $sExtension WinSetTitle($g_hGUI, "", $g_sFileName & " - Notepad") GUICtrlSetState($idSave, $GUI_DISABLE) $g_sText = GUICtrlRead($g_idEdit) EndIf Else Local $iEncoding = FileGetEncoding($g_sOpenFile) If $iEncoding = -1 Then $iEncoding = 128 $sFileSaveDialog = FileSaveDialog("Save As", "::{450D8FBA-AD25-11D0-98A8-0800361B1103}", "Text Documents (*.txt)|All (*.*)", $FD_PATHMUSTEXIST + $FD_PROMPTOVERWRITE, $g_sFileName) If Not @error Then $hFile = FileOpen($sFileSaveDialog, $FO_OVERWRITE + $iEncoding) FileWrite($hFile, GUICtrlRead($g_idEdit)) FileClose($hFile) $g_sOpenFile = $sFileSaveDialog _PathSplit($sFileSaveDialog, $sDrive, $sDir, $sFileName, $sExtension) $g_sFileName = $sFileName & $sExtension WinSetTitle($g_hGUI, "", $g_sFileName & " - Notepad") GUICtrlSetState($idSave, $GUI_DISABLE) $g_sText = GUICtrlRead($g_idEdit) EndIf EndIf EndFunc ;==>_SaveFileAs Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $iCode = BitShift($wParam, 16) Switch $lParam Case $g_hEdit Switch $iCode Case $EN_CHANGE If GUICtrlRead($g_idEdit) <> $g_sText Then WinSetTitle($hWnd, "", "*" & $g_sFileName & " - Notepad") GUICtrlSetState($idSave, $GUI_ENABLE) ; TODO: we will need to add warning/save dialog if user tries to close app or open new file Else WinSetTitle($hWnd, "", "Untitled - Notepad") WinSetTitle($hWnd, "", $g_sFileName & " - Notepad") GUICtrlSetState($idSave, $GUI_DISABLE) EndIf EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND Func AboutDlgProc($hWnd, $iMsg, $wParam, $lParam) Local Const $ID_SCROLL_TIMER = 101 Local Const $aText = [ _ "Notapad (Or Whatever)", _ "Version " & $__g_NotepadVer, _ "", _ "Developed by:", _ "The AutoIt Community", _ "", _ "UI Homage to:", _ "Some Microsoft Developer!", _ "", _ StringFormat("(Sample) Copyleft %s 2026", ChrW(0xD83C) & ChrW(0xDD2F))] Local Static $iScrollY = 0 Local Static $iRefreshInterval = 50 Local Static $iTotalTextHeight = 0 Local Static $iLineHeight = 20 Local Static $hTitleFont ;Vars used with different msgs. just declared up here for now to shut au3check up! Local $hDC, $tPos Switch $iMsg Case $WM_INITDIALOG ;Position: Horz Centre, Vert Top 3rd $tPos = _WinAPI_GetWindowRect($hWnd) Local $hOwner = _WinAPI_GetWindow($hWnd, $GW_OWNER) Local $tOwnerPos = _WinAPI_GetWindowRect($hOwner) Local $tPoint = DllStructCreate($tagPOINT) $tPoint.X = (($tOwnerPos.Right - $tOwnerPos.Left) - ($tPos.Right - $tPos.Left))/2 $tPoint.Y = (($tOwnerPos.Bottom - $tOwnerPos.Top) - ($tPos.Bottom - $tPos.Top))/3 _WinAPI_MapWindowPoints($hOwner, 0, DllStructGetPtr($tPoint), 1) _WinAPI_SetWindowPos($hWnd, 0, $tPoint.X, $tPoint.Y, 0, 0, BitOR($SWP_NOSIZE, $SWP_NOZORDER, $SWP_NOACTIVATE)) $iTotalTextHeight = UBound($aText) * $iLineHeight $iScrollY = $tPos.Bottom - $tPos.Top _WinAPI_SetTimer($hWnd, $ID_SCROLL_TIMER, $iRefreshInterval, 0) ;Copy the font to use for the first line, make it bold. Local $hDlgFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0, 0, "wparam", "lparam", "handle") Local $tDlgLogFont = DllStructCreate($tagLOGFONT) _WinAPI_GetObject($hDlgFont, DllStructGetSize($tDlgLogFont), DllStructGetPtr($tDlgLogFont)) $tDlgLogFont.Weight = $FW_BOLD $hTitleFont = _WinAPI_CreateFontIndirect($tDlgLogFont) Return True Case $WM_NCHITTEST Local $iHit = _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam) _WinAPI_SetWindowLong($hWnd, $DWLP_MSGRESULT, ($iHit = $HTCLIENT) ? $HTCAPTION : $iHit) Return True Case $WM_TIMER If $wParam = $ID_SCROLL_TIMER Then $iScrollY -= 1 If $iScrollY < (0 - $iTotalTextHeight) Then $tPos = _WinAPI_GetWindowRect($hWnd) $iScrollY = $tPos.Bottom - $tPos.Top EndIf _WinAPI_InvalidateRect($hWnd) EndIf Case $WM_DRAWITEM Local Const $tagDRAWITEMSTRUCT = "struct;uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;" & _ "hwnd hwndItem;ptr hDC;long Left;long Top;long Right;long Bottom;ulong_ptr itemData;endstruct" Local $tDrawItem = DllStructCreate($tagDRAWITEMSTRUCT, $lParam) $hDC = $tDrawItem.hDC Local $tRect = DllStructCreate($tagRect, DllStructGetPtr($tDrawItem, "Left")) If $tDrawItem.CtlID = $IDCLOSE Then _WinAPI_DrawEdge($hDC, $tRect, $EDGE_ETCHED, BitOR( $BF_RECT, $BF_FLAT)) _WinAPI_InflateRect($tRect, -1, -1) _WinAPI_DrawText($hDC, "X", $tRect, BitOR($DT_CENTER, $DT_VCENTER)) EndIf Return True Case $WM_ERASEBKGND Return True Case $WM_PAINT Local $tPS = DllStructCreate($tagPAINTSTRUCT) $hDC = _WinAPI_BeginPaint($hWnd, $tPS) ;Double Buffer. paint to me and swap out. Local $tClRect = _WinAPI_GetClientRect($hWnd) Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hMemBMP = _WinAPI_CreateCompatibleBitmap($hDC, $tClRect.Right, $tClRect.Bottom) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hMemBMP) ;old bmp = stock obj, 1x1 monochrome bmp. Local $hBKBrush = _WinAPI_GetSysColorBrush($COLOR_3DFACE) _WinAPI_FillRect($hMemDC, $tClRect, $hBKBrush) _WinAPI_SetBkMode($hMemDC, $TRANSPARENT) _WinAPI_SetTextColor($hMemDC, 0) Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0, 0, "wparam", "lparam", "handle") _WinAPI_SelectObject($hMemDC, $hTitleFont) Local $tTxtRect = DllStructCreate($tagRect) Local $iCurY = $iScrollY For $i = 0 To UBound($aText) - 1 If $i = 1 Then _WinAPI_SelectObject($hMemDC, $hFont) If ($iCurY + 20 > 0) And ($iCurY < $tClRect.Bottom) Then $tTxtRect.Left = 0 $tTxtRect.Top = $iCurY $tTxtRect.Right = $tClRect.Right $tTxtRect.Bottom = $iCurY + $iLineHeight _WinAPI_DrawText($hMemDC, $aText[$i], $tTxtRect, BitOR($DT_CENTER, $DT_NOPREFIX, $DT_NOCLIP)) EndIf $iCurY += $iLineHeight Next _WinAPI_BitBlt($hDC, 0, 0, $tClRect.Right, $tClRect.Bottom, $hMemDC, 0, 0, $SRCCOPY) ;Put 1x1 bmp back so we can destroy real bmp buffer. ;(it needs to be released from dc) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hMemBMP) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPS) Return True Case $WM_COMMAND Local $iNotifCode = _WinAPI_HiWord($wParam) Local $iItemId = _WinAPI_LoWord($wParam) If (Not $lParam) Or ($iNotifCode = $BN_CLICKED) Then Return _Dialog_EndDialog($hWnd, $iItemId) EndIf Case $WM_DESTROY _WinAPI_KillTimer($hWnd, $ID_SCROLL_TIMER) _WinAPI_DeleteObject($hTitleFont) Return True EndSwitch Return False EndFunc WildByDesign 1
WildByDesign Posted September 29 Author Posted September 29 (edited) Notepad 2026-09-29: Added _SaveFileAs_NextName function and _SaveFileAs changes as suggested by @argumentum Added custom About dialog and other changes from @MattyD Added Font... option in Format menu This allows changing font family, size, colour, strikeout, underline, etc. All of these change properly when DPI scaling is changed Added Undo (remember that Undo is single-level undo in Edit controls) Added HotKeys for Open, Save, and Save As Fixed a dialog subclass crash in GUIDarkTheme UDF This was affecting the ChooseFont dialog only Edited September 29 by WildByDesign argumentum 1
WildByDesign Posted September 29 Author Posted September 29 @MattyD Do you have any idea how Microsoft adds the Encoding combobox to the Save As dialog in the classic win32 notepad.exe? If it's too difficult to achieve getting an Encoding combo in the Save As dialog, possibly we can add an Encoding sub-menu in the menu bar to change encoding if anyone needs it.
MattyD Posted September 29 Posted September 29 I need to read upon it properly, but from a skim I'm guessing its this: https://learn.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamew If OFN_EXPLORER is set .... The hook procedure also receives messages for any additional controls that you defined by specifying a child dialog template. If we inspect c:\windows\system32\en-us\notepad.exe.mui, we find something that I'm guessing is that "child dialog template". 15 DIALOGEX 30, 17, 300, 22 STYLE DS_SETFONT | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS CAPTION "" LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US FONT 8, "MS Shell Dlg" { CONTROL "&Encoding:", 259, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE, 68, 1, 40, 40 CONTROL "", 257, COMBOBOX, CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_GROUP | WS_TABSTOP, 130, 0, 164, 100 } WildByDesign 1
WildByDesign Posted September 30 Author Posted September 30 Notepad 2026-09-30: Removed the border from statusbar with $SBT_NOBORDERS Added Select All to Edit menu Added a simple app icon for now from font glyph (until there is a better icon) App icon scales with DPI changes and changes color with theme changes Added app name variable $__g_AppName so that we can easily change the Notepad name Fixed an issue in GUIDarkTheme UDF that was not showing the prefix underline in menu bar when Alt pressed argumentum 1
MattyD Posted October 3 Posted October 3 (edited) On 9/29/2026 at 10:41 PM, WildByDesign said: Do you have any idea how Microsoft adds the Encoding combobox to the Save As dialog in the classic win32 notepad.exe? Ok, so this kinda works, we can add the extra combo. The OFN_EXPLORER flag forces us to use an old fileopen dialog template though, and that's broken with modern versions of explorer (example updated). The method is probably good for Windows XP though expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> #include <Dialogs.au3> Global $g_hFOHookProc = DllCallbackRegister("FileOpenHook", "uint_ptr", "hwnd;uint;wparam;lparam") Global $g_sDialogDll = "Dialog.dll" CreateDialog() DoFileOpen(0) FileDelete($g_sDialogDll) Func CreateDialog() Local $sResName = "DLG_NESTED" FileDelete($g_sDialogDll) _Dialog_Startup() _Dialog_CreateDll($g_sDialogDll) Local $hTemplate = _Dialog_NewTemplate("", 300, 22, 30, 17, BitOR($DS_SETFONT, $DS_CONTROL, $WS_CHILD, $WS_CLIPSIBLINGS), 0) _Dialog_SetFont($hTemplate, "MS Shell Dlg", 8) _Dialog_AddStatic($hTemplate, 259, "&Encoding", 68, 1, 40, 40, BitOR($SS_LEFT, $WS_CHILD, $WS_VISIBLE)) _Dialog_AddComboBox($hTemplate, 257, 130, 0, 164, 100, BitOR($CBS_DROPDOWNLIST, $WS_CHILD, $WS_VISIBLE, $WS_VSCROLL, $WS_GROUP, $WS_TABSTOP)) _Dialog_AddToResource($hTemplate, $sResName, $g_sDialogDll) _Dialog_Shutdown() EndFunc Func DoFileOpen($hParent) Local $g_sDialogDll = "Dialog.dll" Local $hModule = _WinAPI_LoadLibrary($g_sDialogDll) Local $aFilter[][] = [["Text Files", "*.txt"], ["All Files", "*.*"]] Local $sCustomFilter = "Custom Filter" Local $tFilter = DllStructCreate("byte[256]"), $tFilterEntry Local $pFilter = DllStructGetPtr($tFilter) Local $iEntry, $iNumDescChars, $iNumPattChars For $i = 0 To UBound($aFilter) - 1 $iNumDescChars = StringLen($aFilter[$i][0]) + 1 $iNumPattChars = StringLen($aFilter[$i][1]) + 1 If (2*($iNumDescChars + $iNumPattChars + 1) + $iEntry) > DllStructGetSize($tFilter) Then ExitLoop ;Can't fit in buffer $tFilterEntry = DllStructCreate(StringFormat("wchar Desc[%d];wchar Patt[%d]", $iNumDescChars, $iNumPattChars), Ptr($pFilter + $iEntry)) $tFilterEntry.Desc = $aFilter[$i][0] $tFilterEntry.Patt = $aFilter[$i][1] $iEntry += DllStructGetSize($tFilterEntry) Next Local $sCustomFilterDesc = "Custom Filter", $sCustomFilterPattern = "*.*" Local Static $tCustomFilter = DllStructCreate("byte[64]") Local $tCustFilterEntry = DllStructCreate(StringFormat("wchar Desc[%d];wchar Patt[%d]", StringLen($sCustomFilterDesc) + 1, StringLen($sCustomFilterPattern) + 1)) $tCustFilterEntry.Desc = $sCustomFilterDesc $tCustFilterEntry.Patt = $sCustomFilterPattern ;Also recieves filename, or multiple if FO is configured that way Local $tFileNameBuff = DllStructCreate(StringFormat("wchar filenamess[%d]", 256)) $tFileNameBuff.filenames = "SuggestedFile.txt" ;Title name.ext of sel file Local $tFileTitle = DllStructCreate(StringFormat("wchar FileTile[%d]", 64)) ;Suggested init dir. Local $sInitDir = @WorkingDir Local $tInitialDir = DllStructCreate(StringFormat("wchar dir[%d]", StringLen($sInitDir) + 1)) $tInitialDir.dir = $sInitDir ;dlg title Local $sTitle = "Custom Dialog Title" Local $tTitle = DllStructCreate(StringFormat("wchar title[%d]", StringLen($sTitle) + 1)) $tTitle.Title = $sTitle Local $sResName = "DLG_NESTED" Local $tResName = DllStructCreate(StringFormat("wchar Name[%d]", StringLen($sResName) + 1)) $tResName.Name = $sResName Local $tOFN = DllStructCreate($tagOPENFILENAME) $tOFN.StructSize = DllStructGetSize($tOFN) $tOFN.hwndOwner = $hParent $tOFN.hInstance = $hModule $tOFN.lpstrFilter = $pFilter $tOFN.lpstrCustomFilter = DllStructGetPtr($tCustomFilter) $tOFN.nMaxCustFilter = DllStructGetSize($tCustomFilter)/2 $tOFN.nFilterIndex = 0 ;0 = cust filter; 1-n = dropdown. $tOFN.lpstrFile = DllStructGetPtr($tFileNameBuff) $tOFN.nMaxFile = DllStructGetSize($tFileNameBuff)/2 $tOFN.lpstrFileTitle = DllStructGetPtr($tFileTitle) $tOFN.nMaxFileTitle = DllStructGetSize($tFileTitle)/2 $tOFN.lpstrInitialDir = DllStructGetPtr($tInitialDir) $tOFN.lpstrTitle = DllStructGetPtr($tTitle) $tOFN.Flags = BitOR($OFN_DONTADDTORECENT, $OFN_ENABLEHOOK, $OFN_EXPLORER, $OFN_ENABLETEMPLATE) $tOFN.nFileOffset = 0 ;pos of filename in lpstrFile (might conatin path..) $tOFN.nFileExtension = _WinAPI_StringLenW($tFileNameBuff)-3 ;pos of ext in filename. $tOFN.lCustData = 0 ;Passes to hook. $tOFN.lpfnHook = DllCallbackGetPtr($g_hFOHookProc) $tOFN.lpTemplateName = DllStructGetPtr($tResName) ;Template name in res $tOFN.FlagsEx = 0; $OFN_EX_NOPLACESBAR; opt OFN_EX_NOPLACESBAR to hide "favoites" "desktop" etc. Local $aCall = DllCall("Comdlg32.dll", "bool", "GetOpenFileNameW", "struct*", $tOFN) _WinAPI_FreeLibrary($hModule) EndFunc Func FileOpenHook($hWnd, $iMsg, $wParam, $lParam) Switch $iMsg Case $WM_INITDIALOG Local $hCombo = _WinAPI_GetDlgItem($hWnd, 257) _SendMessage($hCombo, $CB_ADDSTRING, 0, "Item 1", 0, "wparam", "wstr") _SendMessage($hCombo, $CB_ADDSTRING, 0, "Item 2", 0, "wparam", "wstr") _SendMessage($hCombo, $CB_ADDSTRING, 0, "Item 3", 0, "wparam", "wstr") _SendMessage($hCombo, $CB_SETCURSEL) Return False EndSwitch Return _WinAPI_CallNextHookEx(0, $iMsg, $wParam, $lParam) EndFunc The correct way of doing things is more like this: expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> Global $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}" Global Const $sIID_IFileOpenDialog = "{d57c7288-d4ad-4768-be02-9d969532d960}" Global Const $sIID_IFileDialogCustomize = "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}" Global Const $tagIFileOpenDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileDialogCustomize = _ "EnableOpenDropDown hresult(dword);" & _ "AddMenu hresult(dword;wstr);" & _ "AddPushButton hresult(dword;wstr);" & _ "AddComboBox hresult(dword);" & _ "AddRadioButtonList hresult(dword);" & _ "AddCheckButton hresult(dword;wstr;bool);" & _ "AddEditBox hresult(dword;wstr);" & _ "AddSeparator hresult(dword);" & _ "AddText hresult(dword;wstr);" & _ "SetControlLabel hresult(dword;wstr);" & _ "GetControlState hresult(dword;dword*);" & _ "SetControlState hresult(dword;dword);" & _ "GetEditBoxText hresult(dword;ptr*);" & _ "SetEditBoxText hresult(dword;wstr);" & _ "GetCheckButtonState hresult(dword;bool*);" & _ "SetCheckButtonState hresult(dword;bool);" & _ "AddControlItem hresult(dword;dword;wstr);" & _ "RemoveControlItem hresult(dword;dword);" & _ "RemoveAllControlItems hresult(dword);" & _ "GetControlItemState hresult(dword;dword;dword*);" & _ "SetControlItemState hresult(dword;dword;dword);" & _ "GetSelectedControlItem hresult(dword;dword*);" & _ "SetSelectedControlItem hresult(dword;dword);" & _ "StartVisualGroup hresult(dword;wstr);" & _ "EndVisualGroup hresult();" & _ "MakeProminent hresult(dword);" & _ "SetControlItemText hresult(dword;dword;wstr);" DoFileOpen(0) Func DoFileOpen($hParent) Local $oFileOpen = ObjCreateInterface($sCLSID_FileOpenDialog, $sIID_IFileOpenDialog, $tagIFileOpenDialog) Local $pCustomFileOpen, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileOpen.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileOpen) Local $oCustomFileOpen = ObjCreateInterface(Ptr($pCustomFileOpen), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local Enum $idVisualGroup = 100, $idCombo, $idItem1, $idItem2, $idItem3 $oCustomFileOpen.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileOpen.AddComboBox($idCombo) $oCustomFileOpen.AddControlItem($idCombo, $idItem1, "Item 1") $oCustomFileOpen.AddControlItem($idCombo, $idItem2, "Item 2") $oCustomFileOpen.AddControlItem($idCombo, $idItem3, "Item 3") $oCustomFileOpen.SetSelectedControlItem($idCombo, $idItem1) $oCustomFileOpen.EndVisualGroup() $oFileOpen.Show($hParent) Local $idSelItem, $sSelItem $oCustomFileOpen.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idItem1 $sSelItem = "Item 1" Case $idItem2 $sSelItem = "Item 2" Case $idItem3 $sSelItem = "Item 3" EndSwitch MsgBox(0, "Selected Item", $sSelItem) EndFunc Edited Saturday at 11:08 PM by MattyD WildByDesign 1
WildByDesign Posted Saturday at 08:31 PM Author Posted Saturday at 08:31 PM 5 hours ago, MattyD said: The correct way of doing things is more like this: This method looks quite good. You've got such a great understanding of how dialogs work under-the-hood. Thanks for sharing these examples. MattyD 1
WildByDesign Posted Saturday at 11:06 PM Author Posted Saturday at 11:06 PM @MattyD My familiarity with any Object-related is essentially equal to zero. It was easy to use AddControlItem to add the text encoding options to the combo and get the returns on those, especially since you've got everything set up so nicely. But the part that I'm not sure about is how to get a return from the File name box as well.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now