The question of a perfect input-box replacement was asked before, but it was never solved.
It must have:
- get immediately input focus
- take default text and
- place the cursor behind the default text
- also should be able to use %ES_PASSWORD
- and have the standard features of the PB-INPUTBOX$
- works with ansi and unicode,
- be High DPI aware.
- don't uses any global variable!
- be of course thread safe.
and it must be just a snap to add it to any program. Just like a
#LINK "JR_Inputbox.sll"
Taking all this it must be something from Jose's window class "CWindow".
And now here is an example how i just copied some code out, modified it a bit and made it into an completely modular SLL.
This way, alll sorts of dialogs can be added to a program just as a SLL!
' ========================================================================================
' Input box dialog
' Parameters:
' - hParent = Handle of the parent window
' - x, y = The location on the screen to display the dialog. If both are 0, the dialog
' is centered on the screem.
' - strCaption = Caption of the window
' - strPrompt = Prompt string
' - strText = Text to edit
' - nLen = Maximum length of the string to edit (default = 260 characters)
' Note: The maximum length is 2048 characters.
' ========================================================================================
#COMPILE SLL "JR_Inputbox.sll"
#DIM ALL
#OPTIMIZE SIZE
#INCLUDE "Win32API.inc"
#INCLUDE "CWindow.inc"
' A01 0/1 - Password or not
#IF %DEF(%UNICODE)
FUNCTION CWindow_InputBox2 (BYVAL hParent AS DWORD, BYVAL strCaption AS WSTRING, BYVAL strPrompt AS WSTRING, BYVAL strText AS WSTRING,OPT BYVAL A01 AS LONG,OPT BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) common AS WSTRING
#ELSE
FUNCTION CWindow_InputBox2 (BYVAL hParent AS DWORD, BYVAL strCaption AS STRING, BYVAL strPrompt AS STRING, BYVAL strText AS STRING,opt A01 as long,opt BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) common AS STRING
#ENDIF
LOCAL hEdit,T01 AS DWORD
#IF %DEF(%UNICODE)
LOCAL szText AS WSTRINGZ * 2049
#ELSE
LOCAL szText AS ASCIIZ * 2049
#ENDIF
if A01 THEN
T01=%ES_Password or %ES_LEFT or %ES_AUTOHSCROLL or %WS_VISIBLE
else
T01=-1
END IF
' // Create an instance of the class
LOCAL pInputBox AS IWindow
pInputBox = CLASS "CWindow"
IF ISNOTHING(pInputBox) THEN EXIT FUNCTION
' // Create the main window
LOCAL hwnd AS DWORD
hwnd = pInputBox.CreateWindow(hParent, strCaption,x,y, 276, 142, _
%WS_VISIBLE or %WS_CAPTION OR %WS_POPUPWINDOW, %WS_EX_DLGMODALFRAME OR %WS_EX_CONTROLPARENT or %WS_EX_TOPMOST, _
CODEPTR(CWindow_InputBox_WindowProc2))
' // Center the window
IF x = 0 AND y = 0 THEN
pInputBox.CenterWindow(hwnd, GetDesktopWindow)
END IF
AfxForceSetForegroundWindow hwnd
' // Add a label control
pInputBox.AddLabel(hwnd, -1 , strPrompt, 21, 10, 240, 19, -1, -1)
' // Add a TextBox control %ES_Password ?
hEdit = pInputBox.AddTextBox(hwnd,_
101,_
"",_ ' Title
21,33,_ ' x,y
230, 19,_ ' With and height
T01,_
-1) ' Ext styles
'SetWindowLong hEdit, %GWL_Style, (GetWindowLong(hEdit,%GWL_Style) Or %ES_Password )
' // Add the buttons
pInputBox.AddButton(hwnd, %IDOK, "&Ok", 21, 72, 75, 22, -1, -1)
pInputBox.AddButton(hwnd, %IDCANCEL, "&Cancel", 176, 72, 75, 22, -1, -1)
' // Set the text
IF nLen = 0 THEN
nLen = 260
ELSE
IF nLen < 1 OR nLen > 2048 THEN nLen = 2048
END IF
SendMessage hEdit, %EM_LIMITTEXT, nLen, 0
IF LEN(strText) > nLen THEN strText = LEFT$(strText, nLen)
SendMessage(hEdit, %WM_SETTEXT, 0, STRPTR(strText))
SendMessage hEdit, %EM_SETSEL, len(strText), -1
' // Set the focus in the edit control
SetFocus hEdit
' // Pointer to the allocated string to return the result
SendMessage hwnd, %WM_USER + 1, VARPTR(szText), 0
' // Default message pump (you can replace it with your own)
pInputBox.DoEvents
' // Enable the parent window
'EnableWindow hParent, %TRUE
SetFocus hEdit
FUNCTION = szText
END FUNCTION
' ========================================================================================
' ========================================================================================
' Editor options callback function.
' ========================================================================================
FUNCTION CWindow_InputBox_WindowProc2 (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
LOCAL nLen AS LONG
#IF %DEF(%UNICODE)
STATIC pText AS WSTRINGZ PTR
#ELSE
STATIC pText AS ASCIIZ PTR
#ENDIF
SELECT CASE uMsg
CASE %WM_CREATE
' // Disable the owner of the modal window
EnableWindow GetWindow(hwnd, %GW_OWNER), %FALSE
CASE %WM_USER + 1
' // Pointer to allocated string to return the result
IF wParam THEN
pText = wParam
EXIT FUNCTION
END IF
CASE %WM_COMMAND
SELECT CASE LO(WORD, wParam)
CASE %IDCANCEL
IF HI(WORD, wParam) = %BN_CLICKED THEN
SendMessage hwnd, %WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
CASE %IDOK
IF HI(WORD, wParam) = %BN_CLICKED THEN
nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXTLENGTH, 0, 0)
IF nLen > 2048 THEN nLen = 2048
nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXT, nLen + 1, pText)
SendMessage hwnd, %WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
END SELECT
CASE %WM_CLOSE
' // The owner window is enabled in WM_CLOSE rather than WM_DESTROY to
' // prevent the application from losing the focus. In WM_DESTROY the
' // modal window has already been removed from the screen by the system.
' // Because the remaining windows are disabled, the system gives the
' // focus to another application.
EnableWindow GetWindow(hwnd, %GW_OWNER), %TRUE
CASE %WM_DESTROY
' // Close the main window
PostQuitMessage 0
EXIT FUNCTION
END SELECT
FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)
END FUNCTION
I am not sure, but your example doesn't work theo. I haven't using SLL examples often yet, but if I look at the code example the statement and parameters for the inputbox aren't complete. I reduced your example to simple exe with cWindow include (why you're using "win32api.inc" too, I think that's no purpose for it if you are working with cWindow.inc". you're idea for another inputbox via SLL I like though :)
' ========================================================================================
' Input box dialog
' Parameters:
' - hParent = Handle of the parent window
' - x, y = The location on the screen to display the dialog. If both are 0, the dialog
' is centered on the screem.
' - strCaption = Caption of the window
' - strPrompt = Prompt string
' - strText = Text to edit
' - nLen = Maximum length of the string to edit (default = 260 characters)
' Note: The maximum length is 2048 characters.
' ========================================================================================
'#COMPILE SLL "JR_Inputbox.sll"
#COMPILE EXE
#DIM ALL
#OPTIMIZE SIZE
'#INCLUDE "Win32API.inc" 'you don't need that one
#INCLUDE "CWindow.inc"
'#IF 0
FUNCTION PBMAIN () AS LONG
LOCAL S01 AS STRING
'S01=CWindow_InputBox2(0,"Hallo","Headline","-")
s01 = CWindow_InputBox2(0, "Hello", "shows an alternative InputBox", "-", 50,50,250,300) 'frank's correction
'MSGBOX s01
END FUNCTION
'#ENDIF
' A01 0/1 - Password or not
'#IF %DEF(%UNICODE)
FUNCTION CWindow_InputBox2(BYVAL hParent AS DWORD, BYVAL strCaption AS WSTRING, BYVAL strPrompt AS WSTRING, BYVAL strText AS WSTRING,OPT A01 AS LONG,OPT BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) COMMON AS WSTRING
'#ELSE
'FUNCTION CWindow_InputBox2 (BYVAL hParent AS DWORD, BYVAL strCaption AS STRING, BYVAL strPrompt AS STRING, BYVAL strText AS STRING,OPT A01 AS LONG,OPT BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) COMMON AS STRING
'#ENDIF
LOCAL hEdit,T01 AS DWORD
'#IF %DEF(%UNICODE)
LOCAL szText AS WSTRINGZ * 2049
'#ELSE
' LOCAL szText AS ASCIIZ * 2049
'#ENDIF
IF A01 THEN
T01=%ES_PASSWORD OR %ES_LEFT OR %ES_AUTOHSCROLL OR %WS_VISIBLE
ELSE
T01=-1
END IF
' // Create an instance of the class
LOCAL pInputBox AS IWindow
pInputBox = CLASS "CWindow"
IF ISNOTHING(pInputBox) THEN EXIT FUNCTION
' // Create the main window
LOCAL hwnd AS DWORD
hwnd = pInputBox.CreateWindow(hParent, strCaption,x,y, 276, 142, _
%WS_VISIBLE OR %WS_CAPTION OR %WS_POPUPWINDOW, %WS_EX_DLGMODALFRAME OR %WS_EX_CONTROLPARENT OR %WS_EX_TOPMOST, _
CODEPTR(CWindow_InputBox_WindowProc2))
' // Center the window
IF x = 0 AND y = 0 THEN
pInputBox.CenterWindow(hwnd, GetDesktopWindow)
END IF
AfxForceSetForegroundWindow hwnd
' // Add a label control
pInputBox.AddLabel(hwnd, -1 , strPrompt, 21, 10, 240, 19, -1, -1)
' // Add a TextBox control %ES_Password ?
hEdit = pInputBox.AddTextBox(hwnd,_
101,_
"",_ ' Title
21,33,_ ' x,y
230, 19,_ ' With and height
T01,_
-1) ' Ext styles
'SetWindowLong hEdit, %GWL_Style, (GetWindowLong(hEdit,%GWL_Style) Or %ES_Password )
' // Add the buttons
pInputBox.AddButton(hwnd, %IDOK, "&Ok", 21, 72, 75, 22, -1, -1)
pInputBox.AddButton(hwnd, %IDCANCEL, "&Cancel", 176, 72, 75, 22, -1, -1)
' // Set the text
IF nLen = 0 THEN
nLen = 260
ELSE
IF nLen < 1 OR nLen > 2048 THEN nLen = 2048
END IF
SendMessage hEdit, %EM_LIMITTEXT, nLen, 0
IF LEN(strText) > nLen THEN strText = LEFT$(strText, nLen)
SendMessage(hEdit, %WM_SETTEXT, 0, STRPTR(strText))
SendMessage hEdit, %EM_SETSEL, LEN(strText), -1
' // Set the focus in the edit control
SetFocus hEdit
' // Pointer to the allocated string to return the result
SendMessage hwnd, %WM_USER + 1, VARPTR(szText), 0
' // Default message pump (you can replace it with your own)
pInputBox.DoEvents
' // Enable the parent window
'EnableWindow hParent, %TRUE
SetFocus hEdit
FUNCTION = szText
END FUNCTION
' ========================================================================================
' ========================================================================================
' Editor options callback function.
' ========================================================================================
FUNCTION CWindow_InputBox_WindowProc2 (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
LOCAL nLen AS LONG
#IF %DEF(%UNICODE)
STATIC pText AS WSTRINGZ PTR
#ELSE
STATIC pText AS ASCIIZ PTR
#ENDIF
SELECT CASE uMsg
CASE %WM_CREATE
' // Disable the owner of the modal window
EnableWindow GetWindow(hwnd, %GW_OWNER), %FALSE
CASE %WM_USER + 1
' // Pointer to allocated string to return the result
IF wParam THEN
pText = wParam
EXIT FUNCTION
END IF
CASE %WM_COMMAND
SELECT CASE LO(WORD, wParam)
CASE %IDCANCEL
IF HI(WORD, wParam) = %BN_CLICKED THEN
SendMessage hwnd, %WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
CASE %IDOK
IF HI(WORD, wParam) = %BN_CLICKED THEN
nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXTLENGTH, 0, 0)
IF nLen > 2048 THEN nLen = 2048
nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXT, nLen + 1, pText)
SendMessage hwnd, %WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
END SELECT
CASE %WM_CLOSE
' // The owner window is enabled in WM_CLOSE rather than WM_DESTROY to
' // prevent the application from losing the focus. In WM_DESTROY the
' // modal window has already been removed from the screen by the system.
' // Because the remaining windows are disabled, the system gives the
' // focus to another application.
EnableWindow GetWindow(hwnd, %GW_OWNER), %TRUE
CASE %WM_DESTROY
' // Close the main window
PostQuitMessage 0
EXIT FUNCTION
END SELECT
FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)
END FUNCTION
and for newbies or beginners with SLL ( like me) shows whole code example with a) SLL building and b) test example how to use it (like handy DLL and test-DLL examples. btw: I've tested your code example and got an error when testing your SLL file with
#COMPILE EXE
#DIM ALL
#INCLUDE "cWindow.inc"
#LINK "JR_Inputbox.sll"
FUNCTION PBMAIN () AS LONG
LOCAL S01 AS STRING
S01=CWindow_InputBox2(0,"Hallo","Headline","-")
'MSGBOX s01
END FUNCTION
'ERROR 632: COMMON name is a duplicate: CWINDOW
best regards, frank
Theo,
Does the error 'ERROR 632: COMMON name is a duplicate: CWINDOW
mean that we can't use it in a program that uses CWindow for other forms?
You should have included a complete test program source. I kept getting the memory error
until I added Frank's extra parameters.
Well, almost. You need to check ISMissing(A01) instead of just testing contents of A01.
Frank,
The last 4 parameters are use Password, x loc, y loc, max len.
Sorry, I can't count.
Theo,
or change A01 to byval.
Frank and Paul, yes you are right, i have done the change.
An optional Parameter must be BYVAL to be able to just check for zero.
Otherwise it may lead to an GPF.
Also the example was from Jose's original Input-Box which is at the end of CWindows.INC.
I took it out and did only few modifications.
Paul, about the Error 632 i can't comment, because i did not get this error here.
Maybe Jose can comment on this?
For what i needed the SLL it works fine, as it is.
If this error would be there it would prevent to have more CWindows Elements linked as SLL's.
Quote
Paul, about the Error 632 i can't comment, because i did not get this error here.
Maybe Jose can comment on this?
I don't use SLLs. If you want to make an input box based in mine, the easiest way is to put the code in an include file. It doesn't take less work to use #LINK "JR_Inputbox.sll" than #INCLUDE "JR_Inputbox.inc". Besides, whereas my input box works both in ansi and unicode thanks to conditional compilation, your SLL won't. Which is the purpose of such a SLL?
Theo,
I'm curious. What benefit does your version of cwindow_inputbox have over the one in
Jose's CWindow.inc ? Aside from being in a SLL which you can't use with a main program
that uses his CWindow.inc .
None. It would have to use a modified version of CWindow with the COMMON keyword added, which will bloat the code. My version was designed to be used as a simple replacement of the input box built in the compiler, that is quite ugly, and to be used modal, not to show a dozen of them at the same time, or to be used in different threads (it uses an static variable; therefore it is not thread safe). Don't you think that if there was any advantage of converting it into a SLL I already would have done it?
Besides, if you compile the SLL without the %UNICODE constant defined, it will be only ansi, and if you define it, it will be only unicode. And it won't be High DPI aware if used with an application that it isn't, or maybe something worse.
Here are the changes to the original version:
I have added this statement:
SendMessage hEdit, %EM_SETSEL, LEN(strText), -1
which is missing in the original version to my knowledge.
Using this, the cursor is behind the default text, not in front of it as in the original version.
Also i have added a way to use a %ES_Password-Textbox if the user should input an password.
For this to be activated i have added an parameter.
Finally i did the great thing and added the word "common" as you know.
As I did not want to change the original thing (because otehrwise any update would destroy my changes) i have copied it and changed the name, added a "2".
I would wish to have a greater choice of predefined dialogs in CWindows.
Like a:
- Timed Textbox
- Textbox with something like "check this, to not show this message again."
and other often used dialogs.