The help search program wrote by Stefan work fine under LB. But Under LBB need some modification to display the list item we clicking on the screen. Any hints or king will be welcome.
Thanks to all
Sarmed
Help Search program?
Re: Help Search program?
The program relies on an undocumented 'feature' of LB 4, which is why it does not work in LBB. The particular feature it is relying on is that, apparently, in LB 4 the listbox string array can include NUL characters: chr$(0). What seems to happen is that the text before the NUL is visible (it can be seen in the listbox) whilst the text after the NUL is invisible; however the entire string, including the NUL, is returned by the selection? command!
This feature is quite surprising and completely undocumented. I have no idea how Stefan discovered it, but obviously by using an undocumented feature he was taking a risk, and it does not work in LBB. To make the program work you would need to find an alternative, documented, way of storing the 'hidden' text.
Richard.
This feature is quite surprising and completely undocumented. I have no idea how Stefan discovered it, but obviously by using an undocumented feature he was taking a risk, and it does not work in LBB. To make the program work you would need to find an alternative, documented, way of storing the 'hidden' text.
Richard.
Re: Help Search program?
The silly thing is that it's quite easy to do it 'properly'. Just create a second array containing the 'hidden' text and then use the selectindex? command instead of the selection? command! I've tried making that change and as far as I can see, on a quick test, the program works:
Code: Select all
' LB Help Search Add-on.bas
' Author: Stefan Pendl
' Date: 24.04.11
'
' Copyright 2011 by Stefan Pendl
'
' This code is free for personal use.
' You may not republish this code in its current form.
' You may modify this code for your personal use.
' You may publish a modified version of this code under these conditions:
' 1. You have made major changes to the code.
' 2. You give credit to the original author
'
' The ATL control code is based on code at http://lbpe.wikispaces.com/ATL+Tutorial
'
'
' Credits:
' Thanks to Alyce, Janet, Chris, Rod, Jack for inspiring me.
' Thanks to the LB community for giving me the opportunity to learn and exchange code.
'
'
' History:
'
' v1.0.0 ... April 24th, 2011 ... Initial release
' v1.0.1 ... April 25th, 2011 ... moved index initialization after opening the window
' v1.0.2 ... -"- ... added static text control, if ATL failed to initialize
' v1.0.3 ... April 26th, 2011 ... added selection of "exact phrase", "all words" or "any word"
' v1.0.4 ... -"- ... added function to build search pattern, source restructured
' v1.0.5 ... -"- ... added selection of "index only", "page contents" or "source code"
' v1.0.6 ... April 28th, 2011 ... added custom resize handler, since native one is only for type window
' v1.0.7 ... April 30th, 2011 ... added Index button to display initial page and index of all pages
' added Usage button to display general usage of this application
' resizer and ATL control are now DPI aware
' v1.0.8 ... -"- ... current settings and window layout are saved on close
' v1.0.9 ... May 1st, 2011 ... making sure the ini file destination folder exists
' save window layout without scaling
' v1.0.10 ... May 2nd, 2011 ... now using a text box instead of the static text control to allow scroll bars
' added more comments in preparation of the final release
' v1.0.11 ... May 7th, 2011 ... added credits
' update list box for each found page during the search
' v1.0.12 ... May 8th, 2011 ... reverted back to Quick Start page as initial page
' v1.0.13 ... -"- ... added hint about ATL context menu for printing
' v1.0.14 ... May 15th, 2011 ... reverted back to index page as initial page
'
' Todo:
' # nothing left to do ;-)
' ################################
' ################################
' ## ##
' ## section for initialization ##
' ## ##
' ################################
' ################################
' check for valid LB version
if val(Version$) < 4.04 then
notice "Wrong LB Version!"; chr$(13);_
"This add-on is only valid for LB v4.04 and above!"; chr$(13);_
"Exiting ..."
end
end if
[InitVars]
' initialize variables
LbInstallDir$ = GetFolder$(GetModuleFileName$())
HelpFileRoot$ = DefaultDir$; "\lb4help\LibertyBASIC_4_web\html\"
HelpFileIndex$ = DefaultDir$; "\lb4help\LibertyBASIC_4.html"
HelpFilePattern$ = "*.htm"
InitialTitle$ = "Index"
InitialPage$ = HelpFileIndex$
' variables for the ini file
AppDataFolder$ = GetEnvironmentVariable$("APPDATA")
LbAppDataFolder$ = GetPathTail$(LbInstallDir$)
IniFileName$ = "LB Help Search Add-on.ini"
ResizerDelay = 250
dim FilesInfo$(1,1), PageIndex$(1,2), FoundPages$(1), FileName$(1)
' initialize ATL control
Open "atl" For DLL As #atl
CallDLL #atl, "AtlAxWinInit", ATLinitialized As long
' ######################################
' ######################################
' ## ##
' ## section for user interface setup ##
' ## ##
' ######################################
' ######################################
[GUI]
' setup GUI
nomainwin
WindowWidth = 800
WindowHeight = 600
UpperLeftX = DisplayWidth - WindowWidth
UpperLeftY = 1
' minimum window size
MinWindowWidth = int(500 * GetScreenScaleForDialog())
MinWindowHeight = int(400 * GetScreenScaleForDialog())
' default size for ATL/text box control
DefaultAtlPosX = 210
DefaultAtlPosY = 10
DefaultAtlWidth = 575
DefaultAtlHeight = 550
' default settings of the radio buttons
AsPhrase$ = "set"
AllWords$ = "reset"
AnyWord$ = "reset"
IndexOnly$ = "set"
PageContents$ = "reset"
SourceCode$ = "reset"
' get the saved layout and settings from the ini file
gosub [ReadDefaults]
' define the GUI
WindowTitle$ = "LB Help Search"
groupbox #m.search, "Search Text", 5, 5, 200, 95
textbox #m.phrase, 15, 20, 180, 25
radiobutton #m.AsPhrase, "As Phrase", [nothing], [nothing], 15, 50, 90, 20
radiobutton #m.AllWords, "All Words", [nothing], [nothing], 105, 50, 90, 20
radiobutton #m.AnyWord, "Any Word", [nothing], [nothing], 15, 70, 90, 20
groupbox #m.source, "Search Source", 5, 105, 200, 65
radiobutton #m.IndexOnly, "Index Only", [nothing], [nothing], 15, 120, 90, 20
radiobutton #m.PageContents, "Page Contents", [nothing], [nothing], 105, 120, 90, 20
radiobutton #m.SourceCode, "Source Code", [nothing], [nothing], 15, 140, 90, 20
button #m.default, "Search", [DoSearch], ul, 5, 175, 60, 25
button #m.index, "Index", [Index], ul, 75, 175, 60, 25
button #m.usage, "Usage", [Usage], ul, 145, 175, 60, 25
groupbox #m.result, "Search Results", 5, 205, 200, 355
stylebits #m.pages, _WS_HSCROLL, 0, 0, 0
listbox #m.pages, FoundPages$(), [DisplayPage], 15, 222, 180, 325
' create the ATL or a text box control
if ATLinitialized then
AtlPosX = int(DefaultAtlPosX * GetScreenScaleForDialog())
AtlPosY = int(DefaultAtlPosY * GetScreenScaleForDialog())
AtlWidth = int(DefaultAtlWidth * GetScreenScaleForDialog())
AtlHeight = int(DefaultAtlHeight * GetScreenScaleForDialog())
else
AtlPosX = DefaultAtlPosX
AtlPosY = DefaultAtlPosY
AtlWidth = DefaultAtlWidth
AtlHeight = DefaultAtlHeight
' the text box will be read-only and include scroll bars
stylebits #m.info, _ES_READONLY or _WS_VSCROLL or _WS_HSCROLL, _ES_AUTOHSCROLL or _ES_AUTOVSCROLL, 0, 0
textbox #m.info, AtlPosX, AtlPosY, AtlWidth, AtlHeight
end if
' create a dilog with a sizing frame and a minimize box
stylebits #m, _WS_THICKFRAME or _WS_MINIMIZEBOX, 0, 0, 0
open WindowTitle$; " - "; InitialTitle$ for dialog as #m
#m "trapclose [quit]"
cursor hourglass
if ATLinitialized then
Message$ = "MSHTML:<html><head></head><body><center><h1>Initializing index!";_
"<br/>Please wait ...</h1></center></body></html>"
hATL = DisplayATL("#m", Message$, hATL, AtlPosX, AtlPosY, AtlWidth, AtlHeight)
else
#m.info "!font 20 bold"
#m.info "Initializing index!"; chr$(13); "Please wait ..."
end if
' create page index
gosub [CreateIndex]
' preset controls
#m.phrase " Enter Search Text "
#m.pages "singleclickselect"
#m.AsPhrase AsPhrase$
#m.AllWords AllWords$
#m.AnyWord AnyWord$
#m.IndexOnly IndexOnly$
#m.PageContents PageContents$
#m.SourceCode SourceCode$
#m.pages "reload"
#m.default "!setfocus"
#m.phrase "!setfocus"
' select entire text in the search box
Handle = hwnd(#m.phrase)
calldll #user32, "SendMessageA",_
Handle as ulong,_
_EM_SETSEL as ulong,_
0 as long,_
-1 as ulong,_
result as long
cursor normal
OldWidth = -1
OldHeight = -1
timer ResizerDelay, [resizer]
' invoke initial resizing
goto [resizer]
' ################################
' ################################
' ## ##
' ## section for event handlers ##
' ## ##
' ################################
' ################################
[nothing]
' dummy event handler for the radio buttons
wait
[Index]
' event handler for the index button
OverridePhrase = 1
[DoSearch]
' event handler for the search and index buttons
cursor hourglass
timer 0
' clear the list box array
redim FoundPages$(FoundFiles)
redim FileName$(FoundFiles)
#m.phrase "!contents? Phrase$"
if Phrase$ = "" or OverridePhrase = 1 then
for i = 1 to FoundFiles
FoundPages$(i) = PageIndex$(i,1)
FileName$(i) = PageIndex$(i,2)
next
else
#m.AsPhrase "value? AsPhrase$"
#m.AllWords "value? AllWords$"
#m.AnyWord "value? AnyWord$"
#m.IndexOnly "value? IndexOnly$"
#m.PageContents "value? PageContents$"
#m.SourceCode "value? SourceCode$"
' build the dynamic search condition
select case
case AnyWord$ = "set"
SearchPattern$ = BuildSearchPattern$(Phrase$, "contents$", "OR", 0)
case AllWords$ = "set"
SearchPattern$ = BuildSearchPattern$(Phrase$, "contents$", "AND", 0)
case else
SearchPattern$ = "instr(upper$(contents$), upper$(Phrase$)) > 0"
end select
' cycle through the pages
j = 1
for i = 1 to FoundFiles
select case
case SourceCode$ = "set"
contents$ = CollectSourceCode$(PageIndex$(i,2))
case PageContents$ = "set"
open PageIndex$(i,2) for input as #f
contents$ = input$(#f, lof(#f))
close #f
case else
contents$ = PageIndex$(i,1)
end select
if eval(SearchPattern$) then
FoundPages$(j) = PageIndex$(i,1)
FileName$(j) = PageIndex$(i,2)
j = j + 1
#m.pages "reload"
end if
next
end if
#m.pages "reload"
#m.pages "selectindex 0"
#m.phrase "!setfocus"
#m.default "!setfocus"
cursor normal
timer ResizerDelay, [resizer]
' wait here if the search button was hit, continue for the index button
if OverridePhrase = 0 then wait
[DisplayPage]
' event handler for the selected list box item and the index button
if OverridePhrase = 1 then
Page$ = InitialTitle$; chr$(0); InitialPage$
else
#m.pages "selectionindex? index"
Page$ = FoundPages$(index); chr$(0); FileName$(index)
end if
FileName$ = word$(Page$, 2, chr$(0))
if ATLinitialized then
hATL = DisplayATL("#m", FileName$, hATL, AtlPosX, AtlPosY, AtlWidth, AtlHeight)
else
#m.info "!font 20 bold"
#m.info "Displaying Pages in your Browser!"
run "rundll32.exe url.dll,FileProtocolHandler "; chr$(34); FileName$; chr$(34)
end if
call SetWindowText "#m", WindowTitle$; " - "; word$(Page$, 1, chr$(0)); chr$(0)
OverridePhrase = 0
wait
[resizer]
' resize handler for the dialog window
' get window size
call GetWindowRect "#m", UpperLeftX, UpperLeftY, WindowWidth, WindowHeight
' check if we match the minimum size
if WindowWidth < MinWindowWidth then WindowWidth = MinWindowWidth
if WindowHeight < MinWindowHeight then WindowHeight = MinWindowHeight
' get desktop size
if GetDesktopRect(DesktopPosX, DesktopPosY, DesktopWidth, DesktopHeight) = 1 then
' check if we are out of bounds
if (UpperLeftX + WindowWidth) > (DesktopPosX + DesktopWidth) then
UpperLeftX = DesktopPosX + DesktopWidth - WindowWidth
end if
if UpperLeftX < DesktopPosX then UpperLeftX = DesktopPosX
if (UpperLeftY + WindowHeight) > (DesktopPosY + DesktopHeight) then
UpperLeftY = DesktopPosY + DesktopHeight - WindowHeight
end if
if UpperLeftY < DesktopPosY then UpperLeftY = DesktopPosY
' check if we exceed the desktop size
if WindowWidth > DesktopWidth then WindowWidth = DesktopWidth
if WindowHeight > DesktopHeight then WindowHeight = DesktopHeight
end if
call SetWindowPos hwnd(#m), UpperLeftX, UpperLeftY, WindowWidth, WindowHeight
' get client area size
if GetClientRect("#m", NewWidth, NewHeight) = 0 then wait
' check if size has changed
if NewWidth = OldWidth and NewHeight = OldHeight then wait
' resize controls
call SetWindowPos hwnd(#m.pages), -1, -1, int(180 * GetScreenScaleForDialog()),_
NewHeight - int((222 + 20) * GetScreenScaleForDialog())
call SetWindowPos hwnd(#m.result), -1, -1, int(200 * GetScreenScaleForDialog()),_
NewHeight - int((205 + 10) * GetScreenScaleForDialog())
if ATLinitialized then
hBrowse = hATL
AtlWidth = NewWidth - AtlPosX - int(10 * GetScreenScaleForDialog())
else
hBrowse = hwnd(#m.info)
#m.info "!contents? hBrowseCaption$"
AtlWidth = NewWidth - int((AtlPosX + 10) * GetScreenScaleForDialog())
end if
AtlHeight = NewHeight - AtlPosY - int(10 * GetScreenScaleForDialog())
call SetWindowPos hBrowse, -1, -1, AtlWidth, AtlHeight
' refresh text box contents
if not(ATLinitialized) then
#m.info ""
#m.info hBrowseCaption$
end if
' remember current size to avoid running the entire handler, if nothing changed
OldWidth = NewWidth
OldHeight = NewHeight
wait
[Usage]
' event handler for the usage button
if UsageMessage$ = "" then
restore [UsageMessage]
' use an infinite loop to read the usage message
while 1
read String$
' break the loop, if we have reached the end of the message definition
if String$ = "@END" then exit while
' filter strings valid only for the ATL control
if left$(String$, 4) = "ATL:" then
if ATLinitialized then
UsageMessage$ = UsageMessage$ + mid$(String$, 5)
else
String$ = ""
end if
else
' replace "\n" by the new-line characters or tag
if instr(String$, "\n") > 0 then
if ATLinitialized then
' filter strings valid only for the static text control
if left$(String$, 7) = "STATIC:" then
String$ = ""
else
String$ = "<br/>"
end if
else
String$ = chr$(13); chr$(10)
end if
end if
' concatenate the message into one long string for easier display
UsageMessage$ = UsageMessage$ + String$
end if
wend
end if
if ATLinitialized then
hATL = DisplayATL("#m", UsageMessage$, hATL, AtlPosX, AtlPosY, AtlWidth, AtlHeight)
else
#m.info "!font courier_new 10"
#m.info UsageMessage$
end if
#m.default "!setfocus"
wait
[quit]
' event handler for closing the dialog
gosub [SaveDefaults]
close #m
Close #atl
end
' #################################
' #################################
' ## ##
' ## section for DATA definition ##
' ## ##
' #################################
' #################################
[UsageMessage]
' definition of the usage message
'
' strings starting with "ATL:" are only valid for the ATL control
' strings starting with "STATIC:" are only valid for the static text control
' strings containing "\n" are replaced by new line characters or tags
data "ATL:MSHTML:<html><head><title>Usage</title></head><body>"
data "ATL:<center><h3>", "LB Help Search Add-On - Usage", "ATL:</h3></center>", "STATIC:\n", "STATIC:\n"
data "ATL:<h4>", "Search Text:", "ATL:</h4>", "STATIC:\n", "STATIC:\n"
data "ATL:<pre>"
data "Text field ... enter text to search for", "\n"
data "As Phrase .... results containing the entered words as is", "\n"
data "All Words .... results containing all entered words", "\n"
data "Any Word ..... results containing at least one of the entered words", "\n"
data "ATL:</pre>"
data "STATIC:\n"
data "ATL:<h4>", "Search Source:", "ATL:</h4>", "STATIC:\n", "STATIC:\n"
data "ATL:<pre>"
data "Index Only ...... search only the title of the pages", "\n"
data "Page Contents ... search the entire page content", "\n"
data "Source Code ..... search only example code contained on the pages", "\n"
data "ATL:</pre>"
data "STATIC:\n"
data "ATL:<h4>", "Buttons:", "ATL:</h4>", "STATIC:\n", "STATIC:\n"
data "ATL:<pre>"
data "Search ... start the search according to the above settings", "\n"
data "Index .... display the initial page and load the list of all pages", "\n"
data "Usage .... display this message", "\n"
data "ATL:</pre>"
data "STATIC:\n"
data "ATL:<h4>", "Search Results:", "ATL:</h4>", "STATIC:\n", "STATIC:\n"
data "ATL:<pre>"
data "Initially ........ contains the list of all pages", "\n"
data "After a Search ... contains the list of matching pages", "\n"
data "ATL:</pre>"
data "ATL:<h4>", "ATL:Printing can be done through the context menu of this control.", "ATL:</h4>"
data "STATIC:\n"
data "ATL:<h4>", "Settings and window layout are saved on close.", "ATL:</h4>"
data "ATL:</body></html>"
data "@END"
' ############################
' ############################
' ## ##
' ## section for procedures ##
' ## ##
' ############################
' ############################
' ##########
' # #
' # GOSUBs #
' # #
' ##########
[SaveDefaults]
' save dialog layout and current settings to the ini file
#m.AsPhrase "value? AsPhrase$"
#m.AllWords "value? AllWords$"
#m.AnyWord "value? AnyWord$"
#m.IndexOnly "value? IndexOnly$"
#m.PageContents "value? PageContents$"
#m.SourceCode "value? SourceCode$"
' make sure the destination folder exists
result = mkdir(AppDataFolder$; "\"; LbAppDataFolder$)
' save the settings only if the folder was created or already exists
if result = 0 or result = 183 then
call GetWindowRect "#m", UpperLeftX, UpperLeftY, WindowWidth, WindowHeight
if UpperLeftX = 0 then UpperLeftX = 1
if UpperLeftY = 0 then UpperLeftY = 1
open AppDataFolder$; "\"; LbAppDataFolder$; "\"; IniFileName$ for output as #ini
#ini "WindowWidth = "; int(WindowWidth / GetScreenScaleForDialog())
#ini "WindowHeight = "; int(WindowHeight / GetScreenScaleForDialog())
#ini "UpperLeftX = "; UpperLeftX
#ini "UpperLeftY = "; UpperLeftY
#ini "AsPhrase = "; AsPhrase$
#ini "AllWords = "; AllWords$
#ini "AnyWord = "; AnyWord$
#ini "IndexOnly = "; IndexOnly$
#ini "PageContents = "; PageContents$
#ini "SourceCode = "; SourceCode$
close #ini
else
notice "Path does not exist"; chr$(13); "Unable to save settings!"
end if
return
[ReadDefaults]
' read dialog layout and last settings from the ini file
files AppDataFolder$; "\"; LbAppDataFolder$, IniFileName$, FilesInfo$()
' only read if file exists
if val(FilesInfo$(0,0)) > 0 then
open AppDataFolder$; "\"; LbAppDataFolder$; "\"; IniFileName$ for input as #ini
while not(eof(#ini))
line input #ini, setting$
Option$ = trim$(word$(setting$, 1, "="))
Value$ = trim$(word$(setting$, 2, "="))
select case Option$
case "WindowWidth"
WindowWidth = val(Value$)
case "WindowHeight"
WindowHeight = val(Value$)
case "UpperLeftX"
UpperLeftX = val(Value$)
case "UpperLeftY"
UpperLeftY = val(Value$)
case "AsPhrase"
AsPhrase$ = Value$
case "AllWords"
AllWords$ = Value$
case "AnyWord"
AnyWord$ = Value$
case "IndexOnly"
IndexOnly$ = Value$
case "PageContents"
PageContents$ = Value$
case "SourceCode"
SourceCode$ = Value$
end select
wend
close #ini
end if
return
[CreateIndex]
' fill page index
files HelpFileRoot$, HelpFilePattern$, FilesInfo$()
FoundFiles = val(FilesInfo$(0,0))
if FoundFiles = 0 then
if ATLinitialized then
Message$ = "MSHTML:<html><head></head><body><center><h1>Unable to locate Help Files!";_
"</h1></center></body></html>"
hATL = DisplayATL("#m", Message$, hATL, AtlPosX, AtlPosY, AtlWidth, AtlHeight)
else
#m.info "Unable to locate Help Files!"
end if
else
redim PageIndex$(FoundFiles,2)
redim FoundPages$(FoundFiles)
redim FileName$(FoundFiles)
for i = 1 to FoundFiles
FileName$ = HelpFileRoot$; FilesInfo$(i,0)
open FileName$ for input as #f
contents$ = input$(#f, min(512, lof(#f)))
close #f
' parsing the tilte tag does not return unique results
' StartPos = instr(upper$(contents$), "<TITLE>") + 7
' EndPos = instr(upper$(contents$), "</TITLE>, StartPos")
' parsing the first bold text does return unique results
' this returns the headline
StartPos = instr(upper$(contents$), "<B>") + 3
EndPos = instr(upper$(contents$), "</B>", StartPos)
PageTitle$ = mid$(contents$, StartPos, EndPos - StartPos)
PageIndex$(i,1) = PageTitle$
PageIndex$(i,2) = FileName$
next
' sort page index
sort PageIndex$(, 1, FoundFiles, 1
' fill list box array with page information
for i = 1 to FoundFiles
FoundPages$(i) = PageIndex$(i,1)
FileName$(i) = PageIndex$(i,2)
next
if ATLinitialized then
hATL = DisplayATL("#m", InitialPage$, hATL, AtlPosX, AtlPosY, AtlWidth, AtlHeight)
else
#m.info "Displaying Pages in your Browser!"
end if
call SetWindowText "#m", WindowTitle$; " - "; InitialTitle$; chr$(0)
end if
return
' ########
' # #
' # SUBs #
' # #
' ########
sub SetWindowPos hWndParent, PosX, PosY, Width, Height
' set window position and size with the ability to ignore one or the other
'
' hWndParent ... handle of the control to position/resize
' PosX ......... horizontal position of the top left corner
' PosX ......... vertical position of the top left corner
' Width ........ new width of the control or window
' Height ....... new height of the control or window
' do not change the z-order and do not activate the window/control
uFlags = _SWP_NOZORDER or _SWP_NOACTIVATE
' ignore the positional arguments, if both are -1
if PosX = -1 and PosY = -1 then uFlags = uFlags or _SWP_NOMOVE
' ignore the size arguments, if both are -1
if Width = -1 and Height = -1 then uFlags = uFlags or _SWP_NOSIZE
calldll #user32, "SetWindowPos",_
hWndParent as ulong,_
_NULL as ulong,_
PosX as long,_
PosY as long,_
Width as long,_
Height as long,_
uFlags as ulong,_
result as long
end sub
sub GetWindowRect Parent$, ByRef PosX, ByRef PosY, ByRef Width, ByRef Height
' get the size of the window or control
'
' Parent$ ... LB handle of the control or window, for instance "#m" or "#m.cb"
'
' on success fills the remaining 4 arguments with the
' size and position of the control/window
hWndParent = hWnd(#Parent$)
struct RECT,_
left as LONG,_
top as LONG,_
right as LONG,_
bottom as LONG
calldll #user32, "GetWindowRect",_
hWndParent as ulong,_
RECT as struct,_
result as long
if result <> 0 then
PosX = RECT.left.struct
PosY = RECT.top.struct
Width = RECT.right.struct - RECT.left.struct
Height = RECT.bottom.struct - RECT.top.struct
end if
end sub
sub SetWindowText Parent$, Caption$
' change the caption of a control or window
'
' Parent$ .... LB handle of the control or window, for instance "#m" or "#m.cb"
' Caption$ ... text for the new caption
hWndParent = hWnd(#Parent$)
calldll #user32, "SetWindowTextA",_
hWndParent as ulong,_
Caption$ as ptr,_
result as long
end sub
' #############
' # #
' # FUNCTIONs #
' # #
' #############
function GetClientRect(Parent$, ByRef Width, ByRef Height)
' get the size of a window
'
' Parent$ .... LB handle of the window, for instance "#m"
'
' on success 1 is returned and the arguments are filled with the values
' on failure 0 is returned
hWndParent = hWnd(#Parent$)
struct RECT,_
left as LONG,_
top as LONG,_
right as LONG,_
bottom as LONG
calldll #user32, "GetClientRect",_
hWndParent as ulong,_
RECT as struct,_
result as long
if result <> 0 then
Width = RECT.right.struct
Height = RECT.bottom.struct
GetClientRect = 1
else
GetClientRect = 0
end if
end function
function GetDesktopRect(ByRef PosX, ByRef PosY, ByRef Width, ByRef Height)
' get the size and position of the desktop area not covered by any tool bars
'
' on success 1 is returned and the arguments are filled with the values
' on failure 0 is returned
struct RECT,_
left as LONG,_
top as LONG,_
right as LONG,_
bottom as LONG
uiAction = _SPI_GETWORKAREA
calldll #user32, "SystemParametersInfoA",_
uiAction as ulong,_
uiParam as ulong,_
RECT as struct,_
fWinIni as ulong,_
result as long
if result <> 0 then
PosX = RECT.left.struct
PosY = RECT.top.struct
Width = RECT.right.struct - RECT.left.struct
Height = RECT.bottom.struct - RECT.top.struct
GetDesktopRect = 1
else
GetDesktopRect = 0
end if
end function
function CollectSourceCode$(FileName$)
' this function parses HTML pages for source code sections
' and returns a concatenated string of them
' source code in LBs help file is defined by the font "Courier New"
StartCode$ = "<FONT FACE="; chr$(34); "COURIER NEW"; chr$(34); " SIZE="; chr$(34); "2"; chr$(34); ">"
open FileName$ for input as #f
contents$ = input$(#f, lof(#f))
close #f
StartPos = 0
EndPos = 1
' use an infinite loop for parsing
while 1
StartPos = instr(upper$(contents$), StartCode$, EndPos)
' break out of the loop, if there is nothing found
if StartPos = 0 then exit while
StartPos = StartPos + len(StartCode$)
EndPos = instr(upper$(contents$), "</FONT>", StartPos)
CollectSourceCode$ = CollectSourceCode$; "<br/>"; mid$(contents$, StartPos, EndPos - StartPos)
wend
end function
function BuildSearchPattern$(SearchString$, ContainerVar$, Operator$, CaseSensitive)
' return a string containing a conditional statement to be executed by the EVAL() function
'
' SearchString$ ... string containing the search term
' ContainerVar$ ... variable containing the string to be searched
' Condition$ ...... boolean operator to concatenate multiple conditions (AND/OR/XOR)
' CaseSensitive ... flag to create a case sensitive contition or not
' 1 ... case sensitive
' 0 ... case insensitive
count = 1
' build condition for first word of the search term
if CaseSensitive then
BuildSearchPattern$ = "instr("; ContainerVar$; ", ";_
chr$(34); word$(SearchString$, count); chr$(34); ") > 0"
else
BuildSearchPattern$ = "instr(upper$("; ContainerVar$; "), ";_
chr$(34); upper$(word$(SearchString$, count)); chr$(34); ") > 0"
end if
count = count + 1
' add remaining conditions separated by the operator
while word$(SearchString$, count) <> ""
if CaseSensitive then
BuildSearchPattern$ = BuildSearchPattern$; " "; Operator$; " instr("; ContainerVar$; ", ";_
chr$(34); word$(SearchString$, count); chr$(34); ") > 0"
else
BuildSearchPattern$ = BuildSearchPattern$; " "; Operator$; " instr(upper$("; ContainerVar$; "), ";_
chr$(34); upper$(word$(SearchString$, count)); chr$(34); ") > 0"
end if
count = count + 1
wend
end function
function DisplayATL(Parent$, File$, Handle, PosX, PosY, Width, Height)
' create an ATL control
'
' Parent$ ... LB handle of the parent window, for instance "#m"
' File$ ..... Path of a file, HTML code as a string or an URL
' see http://lbpe.wikispaces.com/ATL+Tutorial for more
' Handle .... Windows handle of the last created ATL control
' usually the handle returned by the last call of this function
'
' on success returns the handle of the created control
if Handle then
CallDLL #user32, "DestroyWindow", _
Handle As ulong, _
result As long
end if
hWndParent = hWnd(#Parent$)
CallDLL #user32, "GetWindowLongA", _
hWndParent As ulong, _
_GWL_HINSTANCE As long, _
hInst As ulong
style = _WS_CHILD or _WS_VISIBLE or _WS_VSCROLL or _WS_HSCROLL or _WS_BORDER
exStyle = _WS_EX_CLIENTEDGE or _WS_EX_TOPMOST
CallDLL #user32, "CreateWindowExA", _
exStyle As ulong, _
"AtlAxWin" As ptr, _
File$ As ptr, _
style As ulong, _
PosX As long, _
PosY As long, _
Width As long, _
Height As long, _
hWndParent As ulong, _
_NULL As ulong, _
hInst As ulong, _
_NULL As ulong, _
DisplayATL As ulong
end function
function GetFolder$(Path$)
' strip off the part after the last backslash of a file or folder path
pos = 1
GetFolder$ = Path$
while pos > 0
pos = instr(Path$, "\", pos)
if pos > 0 then
GetFolder$ = left$(Path$, pos)
pos = pos + 1
end if
wend
end function
function GetPathTail$(Path$)
' get the part after the last backslash of a file or folder path
if right$(Path$, 1) = "\" then
GetPathTail$ = left$(Path$, len(Path$)-1)
else
GetPathTail$ = Path$
end if
for pos = len(GetPathTail$) to 1 step -1
if mid$(GetPathTail$, pos, 1) = "\" then exit for
next
if pos > 1 then GetPathTail$ = mid$(GetPathTail$, pos + 1)
end function
function GetModuleFileName$()
' return the full path of the executable of the current process
nSize = _MAX_PATH + 1
lpFilename$ = space$(nSize); CHR$(0)
calldll #kernel32, "GetModuleFileNameA",_
hModule as uLong,_
lpFilename$ as ptr,_
nSize as uLong,_
result as uLong
if result > 0 then GetModuleFileName$ = trim$(lpFilename$)
end function
function GetScreenScaleForDialog()
' get the scale to size controls inside a dialog type window
'
' controls of dialog type windows are automatically scaled
' to match the users screen DPI settings
'
' LB does not use all scales, only 100% and 125%
calldll #user32, "GetDC",_
0 as ulong,_ ' entire screen
hDC as ulong
nIndex = _LOGPIXELSX
calldll #gdi32, "GetDeviceCaps",_
hDC as ulong,_
nIndex as ulong,_
dpi as ulong
calldll #user32, "ReleaseDC",_
0 as ulong,_ ' entire screen
hDC as ulong,_
result as ulong ' 1 = success
ScreenScale = dpi / 96
ScreenScaleTmp = max(1, ScreenScale)
GetScreenScaleForDialog = min(1.25, ScreenScaleTmp)
end function
function GetEnvironmentVariable$(lpName$)
'get the value of an environment variable
nSize = 1024
[Retry]
lpBuffer$ = space$(nSize)
calldll #kernel32, "GetEnvironmentVariableA", _
lpName$ as ptr, _
lpBuffer$ as ptr, _
nSize as ulong, _
result as ulong
select case
' buffer too small
case result > nSize
nSize = result
goto [Retry]
' variable found
case result > 0
GetEnvironmentVariable$ = trim$(lpBuffer$)
end select
end function
-
- Posts: 37
- Joined: Fri Apr 06, 2018 6:27 am
Re: Help Search program?
Thank you, Richard,
It 's clear now.
All the best,
It 's clear now.
All the best,
Re: Help Search program?
(my guess that)
It is OK with BASIC strings to contain chr(0)
but Windows uses C library to work with strings - where \0 is string terminator
So we got string printed up to first chr(0).
It is in the lore - I know it from somewhere.
As for using undocumented / incompatible features - if one program only in ONE language he rarely even thinks of using other ways beside first one that works.
EDIT and totally oblivious as to if it could fail and why (speaking of myself)
For example, LBB "x++" is incompatible with LB.
(EDIT-2 10.04,2018 Actually not x++ but x+=3)
But if one not using LB he would never know that.
Could programs be written without it? Yes.
Does not using it worths it? Depends on the goal.
EDIT
this one works the same in LB/LBB - only first part is visible
It is OK with BASIC strings to contain chr(0)
but Windows uses C library to work with strings - where \0 is string terminator
So we got string printed up to first chr(0).
It is in the lore - I know it from somewhere.
As for using undocumented / incompatible features - if one program only in ONE language he rarely even thinks of using other ways beside first one that works.
EDIT and totally oblivious as to if it could fail and why (speaking of myself)
For example, LBB "x++" is incompatible with LB.
(EDIT-2 10.04,2018 Actually not x++ but x+=3)
But if one not using LB he would never know that.
Could programs be written without it? Yes.
Does not using it worths it? Depends on the goal.
EDIT
this one works the same in LB/LBB - only first part is visible
Code: Select all
a$="hello"+chr$(0)+"there"
notice a$
Last edited by tsh73 on Tue Apr 10, 2018 5:23 pm, edited 1 time in total.
Re: Help Search program?
It's not surprising that only the string before the NUL is visible - that is to be expected and both LB 4 and LBB behave the same way. What is more surprising is that the selection? command returns the whole string, including the NUL. It implies that selection? is returning the contents of the array, not the contents of the listbox, as it does in LBB.
If you were to modify the contents of the listbox using Windows API calls, resulting in it no longer corresponding to the array, I guess LB 4 would return the contents of the array even if what is displayed in the listbox is completely different!
That is poor quality coding; no professional programmer would work that way. If you rely on an undocumented feature, even if you use only the one language, there is no guarantee that it will work consistently, or that it will behave the same way after an upgrade. You refer to the "first way that works", but just because it worked five minutes ago it doesn't mean that it will necessarily work in five minutes time! You are taking a risk, always, when using any undocumented feature.As for using undocumented / incompatible features - if one program only in ONE language he rarely even thinks of using other ways beside first one that works.
Sadly the documentation of Liberty BASIC is incomplete, so sometimes you have to use an undocumented feature simply because it has been omitted (the CHAR[N] structure type is a good example). But that doesn't mean it's OK to use other undocumented features just because they seem to work.
Richard.