'Editor for PowerBasic and FreeBasic by Roland Walter.
'The executable and the sources are under GPL license.
'
'Last change:           10.October 1012
'Programmer:            Roland Walter, support@rowalt.de, www.rowalt.de
'Programming language:  PowerBasic 10.00 (see www.powerbasic.com and www.powerbasic.de)
'
'History:
' - 0.9.0.0 - First public version, the preceding program was named "PBE" (PowerBasicEditor) with own version numbers.
' - 0.9.0.1 - Spelling error: "indend" corrected to "indent".
'           - Some more colors added for syntax coloring.
'           - Basic keywords and API keywords now can have different colors. For this BeScin.dll has been changed.
'           - BeScin.dll is updated to version 1.6.1.2 for the separated keyword lists.
'           - Constant keyword list added for FreeBasic, which enables syntax coloring.
'           - Code formatter added to correct the entire listing, see menu "Tools". Changes the sizes of API and Basic
'             keywords and constants. More options are still to do (for example correction of indentions).
' - 0.9.0.2 - Now the listing head (part before the first sub/function/macro) can be toggled to a single line. The first line
'             stays visible in this case.
'           - In Project settings the file selection dialogs now are opened with home directory of loaded Basic file (tnx to Cactus)
' - 0.9.0.x - You now can toggle (open/close) the listing head as it whould be a function
' - 0.9.0.3 - Key shortcuts changed for better compatibility to other programs: "Save": Ctrl+S, "Save As...": F12
' - 0.9.0.4 - Minor changes for PBWin 10.0
'           - Bug: Resource editor got incorrect Path+FileName if spaces were in path
'
'Bugs in BE project setting (by Cactus): can not pass Compiler parameter.
'
'Some further ideas I could realize if there is enough time for:
' - Remember last 4...8 files in menu "File"
' - Enable toggling of very first listing part (before the first function) - Usefull or confusing?
' - Search again using F3 with opened and/or closed Search dialog
' - Save last used search case (and so on) in Search/Replace dialog
' - Make replacing faster (not simple to solve for the moment because Scintilla is responsible)
' - Backup of last successfull compiled Basic file
' - PowerBasic: Project settings: Link resources alternatively using RLINK32.EXE, produce console program with PbWin and so on
' - Font dialog: Check handling of not existing fonts
' - GoTo-Dialog: Show current line in dialog
' - Free configurable Tool menu for other help files and tools
' - Enable use of relative pathes (makes ini file portable)
' - PbDos compiler: Completly other and much more command line options! PBC.EXE [options] FILENAME [options]
'   Example PBC.EXE -Ce -DSC:\PB\INCLUDE TEST.BAS
'   -Ce compiles to an .EXE file (default)
'   -DSpath[;path...] Source directories path, example: PBC.EXE TEST.BAS -DSC:\PB\INCLUDE;D:\INC
' - Idea: Checkbox in "Open file" dialog: "Load with new window"
'
'Hints:
'The editor bases on the Scintilla edit control which You can downlad from www.scintilla.org. BeScin.dll is an inofficial version
'of the Scintilla DLL which has a PowerBasic lexer only for size reasons. The PowerBasic lexer is usefull for FreeBasic too as
'You see. The PowerBasic lexer I had to write by myself because the available lexers didn't fit my own needs.
'The Scintilla window is controlled by messages similar to the RichEdit control. Above it's possible to send these messages
'directly to the Scintilla window function which enhances the performance significantly. For this feature use SendScintillaMsg()
'instead of SendMessage().
'For BeScin.dll the entire official Scintilla documentation is valid. The lexer specific information You can find in BeScin.inc.
'*************************************************************************************************************************************
#Compile Exe "BE.EXE"        'Compile a program
#Dim All                     'All variables must be declared
#Option Version4             '>= NT 4.0/Windows 95
#Tools Off                   'No debug code, if Trace, Profile and so on used in code
#Resource Res "BE.Res"       'The resorce file (menus, dialogs, icons...)
#Include "WIN32API.INC"
#Include "COMDLG32.INC"
'*************************************************************************************************************************************
'Instead of >#Include "HTMLHELP.INC"<:     (for HTML help files)
Declare Function HtmlHelp Lib "hhctrl.ocx" Alias "HtmlHelpA"(ByVal hwndCaller As Dword,pszFile As Asciiz,ByVal uCommand As Dword,ByVal dwData As Dword) As Dword
%HH_CLOSE_ALL            = &H0012  'Close all windows opened directly or indirectly by the caller
%HH_DISPLAY_INDEX        = &H0002
'*************************************************************************************************************************************
'Instead of >#Include "RICHEDIT.INC"<:     (for the program help window which is a RichEdit control)
Type EDITSTREAM Dword
  dwCookie As Dword
  dwError As Dword
  pfnCallback As Dword
End Type
%EM_STREAMIN  = %WM_USER+73
%SF_RTF       = &H0002
%SFF_PLAINRTF = &H4000
'*************************************************************************************************************************************
#Include "BEscin.inc"  'Scintilla edit control declarations
'*************************************************************************************************************************************
'Some string constants which are used several times:
$APP_NAME            ="Basic Editor by Roland Walter"
$APP_NAME_SHORT      ="Basic Editor"
$WNDCLASS_MAIN       ="BeRowaltClass"                   'The Main windows's class name
'$DLGCLASS_EDITORHELP ="BeRowaltHlpDlgClass"             'The Help dialog windows's class name
'
$TEXT_IS_CHANGED    ="The text was been changed."
$CANCEL_QUESTION    ="Cancel operation?"
$TEXT_CHANGE_IT     ="Save changes?"
$NO_FILENAME_SAVE   ="The editor content isn't saved as file. Save now?"
'
'String constants used as keys for ini file:
$PATH                ="PathSettings"          'Section name
$LASTFILE            ="LastFile"
$INCLUDEDIR          ="IncludeDir"
$TEMPLATEDIR         ="TemplateDir"
$BASICHELPFILE       ="BasicHelpFile"
$APIHELPFILE         ="ApiHelpFile"
$COMPILERFILE        ="Compiler"
$PBRESTOOLFILE       ="PbResourceConverter"
$BASICKEYWORDFILE    ="BasicKeywordFile"
$CONSTANTKEYWORDFILE ="ConstantKeywordFile"
$APIKEYWORDFILE      ="ApiKeywordFile"
$RESEDITFILE         ="ResourceEditor"
$WINDOWS             ="Windows"               'Section name
$MAINWNDPOS          ="MainWndPos"
$AUTOINDENT          ="AutoIndent"
$AUTOCASECORRECTION  ="AutoCaseCorrection"
$SEARCHWNDPOS        ="SearchWndPos"
$GOTOWNDPOS          ="GoToWndPos"
$SYNTAXCOLORS        ="SyntaxColors"
$FONTNAME            ="Font"
$FONTSIZE            ="FontSize"
$SEARCHKEYWORD       ="LastSearchKey"
$REPLACEKEYWORD      ="LastReplaceKey"
$OTHERSETTINGS       ="OtherSettings"         'Section name
$COMPILETIMEOUT      ="CompileTimeout"
$COMPILERTYPE        ="CompilerType"
'
'String constants used to store the file's current settings and the project settings at the very end of the loaded file:
$PBESETTINGS      =Chr$(13,10)+"'PBESETTINGS="  'Replaced by $BESETTINGS since FreeBasic support added (string needed for auto-conversion)
$BESETTINGS       =Chr$(13,10)+"'BESETTINGS (don't change!):"   'Start of setting block at end of file
$BECURSOR         =Chr$(13,10)+"'BECURSOR="     'Hex number coding current cursor position
$BETOGGLE         =Chr$(13,10)+"'BETOGGLE="     'List of "1" or "0" presenting the toggle state of the subs/functions/macros.
$BETARGET         =Chr$(13,10)+"'BETARGET="     'Hex number coding the project's target file type (%TARGET_... constant)
$BERESFILE        =Chr$(13,10)+"'BERESFILE="    'Resource filename (*.res) as plain text
$BEOUTFILE        =Chr$(13,10)+"'BEOUTFILE="    'Output filename (if specified) as plain text
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'Supported compilers:
%CMPTYPE_FREEBASIC   = 0          'FreeBasic compiler  (must (!!!) have the slowest ID of the supported compilers)
%CMPTYPE_POWERBASIC  = 1          'PowerBasic compiler
%CMPTYPE_UNKNOWN     = 2          'For invalid values (user has hacked the ini file), must be highest legal ID plus 1
'
'Project setting constants (for type T_PROJECTSETTINGS):
'Target file type:
%TARGET_WIN32_CONSOLE = 0         'Win32 co&nsole application (*.exe)
%TARGET_WIN32_GUI     = 1         'Win32 &GUI application (*.exe)
%TARGET_WIN32_DLL     = 2         'Win32 &dynamic library (*.dll)
%TARGET_WIN32_LIB     = 3         'Win32 &static library (*.lib)
%TARGET_WIN32_OBJ     = 4         'Win32 o&bject file (*.obj)
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'Resource IDs for the program help which is a RTF file stored as user defined resource
%IDREST_EDITORHELP        = 500   'User defined resource type used for the editor's help
%IDRES_EDITORHELP          = 1     'Resource ID for the resource containing the RTF file with the program help
'%IDRES_EDITORHELP_CONTENT = 1     'Resource ID for the resource containing the RTF file with the program help
'%IDRES_EDITORHELP_FBSTART = 2     'Resource ID for the resource containing the RTF file with the program help
'%IDRES_EDITORHELP_PBSTART = 3     'Resource ID for the resource containing the RTF file with the program help
'
%IDREST_KEYWORDS          = 501   'User defined resource type used for the syntax-coloring keywords
%IDRES_APIKEYWORDS        = 1     'Resource ID for the resource containing the API keyword list
%IDRES_FREEBASICKEYWORDS  = 2     'Resource ID for the resource containing the FreeBasic keyword list
%IDRES_POWERBASICKEYWORDS = 3     'Resource ID for the resource containing the PowerBasic keyword list
%IDRES_CONSTANTKEYWORDS   = 4     'Resource ID for the resource containing the Constant keyword list (not needed for PowerBasic)
'
'Menu/Control IDs:
'Main window
%IDC_SCINTILLA            = 1000
'Main window, menu "File":
%IDC_NEWFILE_EMPTY        = 1100
%IDC_NEWFILE_BY_TEMPLATE  = 1101
%IDC_NEW_WINDOW           = 1105
%IDC_OPEN_FILE            = 1110
%IDC_OPEN_VIRTUAL         = 11101 'Virtual control as PostMessage target, loads file without file selection box
%IDC_SAVE                 = 1111
%IDC_SAVE_AS              = 1112
'%IDC_PRINT               = 1120
%IDC_EXIT_APP             = 1180
%IDC_LASTFILE_1           = 1191
%IDC_LASTFILE_2           = 1192
%IDC_LASTFILE_3           = 1193
%IDC_LASTFILE_4           = 1194

'Main window, menu "Edit":
%IDC_UNDO                 = 1200
%IDC_CUT                  = 1201
%IDC_COPY                 = 1202
%IDC_PASTE                = 1203
%IDC_SELECT_ALL           = 1204
%IDC_SERACH_REPLACE       = 1210
%IDC_GOTO_LINE            = 1211
%IDC_TOGGLE_SUB           = 1220
%IDC_TOGGLE_ALL_SUBS      = 1221
%IDC_BLOCKCOMMENT         = 1230  'Block comment
%IDC_BLOCKUNCOMMENT       = 1231  'Block uncomment
%IDC_BLOCKINDENT          = 1232  'Block indent
%IDC_BLOCKUNINDENT        = 1233  'Block unindent

'Top level menu entries:
%IDC_COMPILE              = 1301
%IDC_RUN                  = 1302
'Main window, menu "Tools":
%IDC_COMPILE              = 1301   'Repetition from top level menu (mainly to show the shortcut key, but can be used too)
%IDC_RUN                  = 1302   'Repetition from top level menu (mainly to show the shortcut key, but can be used too)
%IDC_EDIT_RES             = 1311
%IDC_UPDATE_PBRES         = 1312
%IDC_CODECORRECTOR        = 1321
'Main window, menu "Options":
%IDC_FONT_SETTINGS        = 1401
%IDC_GENERAL_SETTINGS     = 1402
%IDC_PROJECT_SETTINGS     = 1403
%IDC_AUTOINDENT           = 1411
%IDC_AUTOCASECORRECTION   = 1412
'Main window, menu "Help":
%IDC_HELP_KEYWORD         = 1900
%IDC_HELP_BASIC           = 1901
%IDC_HELP_API             = 1902
%IDC_HELP_EDITOR          = 1903
%IDC_HELP_ABOUT           = 1909
%IDC_TOGGLE_SUBLIST       = 9999    'Virtual control as PostMessage target,opens/closes subs given by a list
'
'Dialog box "Search/Replace":
%IDD_SEARCH_REPLACE       = 1      'Dialog resource ID
%IDC_SEARCH               = 1      'Button "Search"
%IDC_DONE                 = 2      'Button "Done"
%IDC_REPLACE              = 123    'Button "Replace"
%IDC_REPLACE_ALL          = 124    'Button "Replace all"
%IDC_SEARCH_EDIT          = 101    'Edit control for the string to find or replace
%IDC_REPLACE_EDIT         = 102    'Edit control for the replacement string
%IDC_SRCH_WORD            = 111    'CheckBox "Whole word"
%IDC_SRCH_CASE            = 112    'CheckBox "Match case"
'
'Dialog box "GoTo line":
%IDD_GOTO                 = 2      'Dialog resource ID
%IDC_GOTO_EDIT            = 100
'
'Dialog box "General settings":
%IDD_GENSETTINGSDLG       = 3      'Dialog resource ID
%IDC_GS_TEMPDIR           = 110    'Template directory with...
%IDC_GS_TEMPDIR_S         = 111    '...file selection button
%IDC_GS_INCLUDEDIR        = 120    'Include directory with...
%IDC_GS_INCLUDEDIR_S      = 121    '...file selection button
%IDC_GS_COMPILER          = 130    'PB Compiler (pbdll.exe/pbdll16.exe/pbwin.exe) with...
%IDC_GS_COMPILER_S        = 131    '...file selection button
%IDC_GS_RESCONVERTER      = 140    'PB Resource converter (pbres.exe) with...
%IDC_GS_RESCONVERTER_S    = 141    '...file selection button
%IDC_GS_RESEDITOR         = 150    'Resource editor (must be able to load *.res files, for example Borland Resource Workshop) with...
%IDC_GS_RESEDITOR_S       = 151    '...file selection button
%IDC_GS_APIHELP           = 160    'API help file with...
%IDC_GS_APIHELP_S         = 161    '...file selection button
%IDC_GS_BASICHELP         = 170    'Basic help file with...
%IDC_GS_BASICHELP_S       = 171    '...file selection button
%IDC_GS_BASICKEYLIST      = 180    'Basic keyword list file with...
%IDC_GS_BASICKEYLIST_S    = 181    '...file selection button
%IDC_GS_APIKEYLIST        = 190    'API keyword list file with...
%IDC_GS_APIKEYLIST_S      = 191    '...file selection button
%IDC_GS_CONSTANTKEYLIST   = 200    'Constant keyword list file with...
%IDC_GS_CONSTANTKEYLIST_S = 201    '...file selection button
%IDC_GS_COMPILER_FB       = 301    'RadioButton: Compiler type FreeBasic  (must (!!!) have the slowest of the supported compilers)
%IDC_GS_COMPILER_PB       = 302    'RadioButton: Compiler type PowerBasic
%IDC_GS_QUICKHELP         = 1000   'Quick help STATIC control
'
'Directory selection dialog box (template for GetSaveFileName):
%IDD_DIRSELECT            = 4      'Dialog resource ID
'
'Font+Colors selection dialog box:
%IDD_FONTDLG              = 5      'Dialog resource ID
%IDC_FS_FONTNAME          = 100    'Combobox for font name selection
%IDC_FS_FONTSIZE          = 101    'Combobox for font size
%IDC_FS_APIKEYWORDS       = 201    'Button for "API Keywords" color selection
%IDC_FS_BASICKEYWORDS     = 202    'Button for "Basic Keywords" color selection
%IDC_FS_STRINGS           = 203    'Button for "Strings" color selection
%IDC_FS_NUMBERS           = 204    'Button for "Numbers" color selection
%IDC_FS_OPERATORS         = 205    'Button for "Operators" color selection
%IDC_FS_COMMENTS          = 206    'Button for "Comments" color selection
%IDC_FS_CONSTANTS         = 207    'Button for "Constants" color selection
%IDC_FS_ASM               = 208    'Button for "Assembler" color selection
%IDC_FS_DEFAULT           = 209    'Button for "Default" color selection
'
'Child dialog added to file selection common dialog:
%IDD_FILESELDLG           = 6         'Dialog resource ID
%IDC_FIRSTLINIE           = 10001     'Static text control showing the first line of the selected file
%IDC_GOTOCURDIR           = 10101     'RadioButton "Current directory"
%IDC_GOTOINCDIR           = 10102     'RadioButton "Include directory"
%IDC_OFN_FILENAME         = &H0480    'EDIT-Control "Dateiname" (default common dialog control edt1, see DLGS.H)
%IDC_OFN_FILETYPE         = &H0470    'ComboBox "Dateityp" (default common dialog control cmb1, see DLGS.H)
%IDC_OFN_DIRECTORY        = &H0471    'ComboBox "Suchen in" (default common dialog control cmb2, see DLGS.H)
%IDC_OFN_FILELIST         = &H0460    'Listbox for files and sub diurectories (default common dialog control lst1, see DLGS.H)
%IDC_OFN_OPENSAVE         = %IDOK     'PushButton "Öffnen" or "Speichern" (default common dialog control, see DLGS.H)
%IDC_OFN_CANCEL           = %IDCANCEL 'PushButton "Abbrechen" (default common dialog control, see DLGS.H)
%IDC_OFN_HELP             = &H040E    'PushButton "Hilfe" (default common dialog control pshHelp=psh15, see DLGS.H)
%IDC_OFN_OPENREADONLY     = &H0410    'CheckBox "Open read only" (default common dialog control chx1, see DLGS.H)
'
'Compiler output dialog:
%IDD_COMPILEROUTPUT       = 7         'Dialog resource ID
%IDC_COMPILEROUTPUT       = 100       'EDIT control for the compiler output text
'
'Project settings dialog:
%IDD_PROJECTSETTINGSDLG   = 8         'Dialog resource ID
%IDC_PRJ_TARGETFILETYPE   = 101       'Combobox "Target file", entries in the order of the %TARGET_ IDs
%IDC_PRJ_RESFILENAME      = 111       'EDIT control "Resource file"
%IDC_PRJ_RESFILENAME_S    = 112       'PushButton "Select resource file"
%IDC_PRJ_TARGETFILENAME   = 121       'EDIT control "Target filename"
%IDC_PRJ_TARGETFILENAME_S = 122       'PushButton "Select target filename"
%IDC_PRJ_QUICKHELP        = 1000      'Quick help STATIC control
'
'Code formatter dialog:
%IDD_CODEFORMATTERDLG     = 9         'Dialog resource ID
%IDC_CF_BAS_KEYWORDS      = 100       'Checkbox "Change Basic keywords"
%IDC_CF_API_KEYWORDS      = 110       'Checkbox "Change API keywords"
%IDC_CF_CONST_KEYWORDS    = 120       'Checkbox "Change constants"
%IDC_CF_QUICKHELP         = 1000      'Quick help STATIC control
'
'Editor Help dialog:
%IDD_EDITORHELP           = 10         'Dialog resource ID
%IDC_HLP_HLPTEXT          = 100       'Richedit control for the help text
%IDC_HLP_SEARCHPAGE       = 200       'Search page Edit control
%IDC_HLP_PAGESELBOX       = 300       'Listbox
'
'FreeBasic Help dialog:               ---> Help works with external text files
%IDD_FB_TXT_HELP           = 11       'Dialog resource ID
%IDC_THLP_HLPTEXT          = 100      'Richedit control for the help text
%IDC_THLP_SEARCHPAGE       = 200      'Search page Edit control
%IDC_THLP_PAGESELBOX       = 300      'Content listbox
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'Global variables:
Global hInst As Dword                       'Application Instance handle
Global hWndMain As Dword                    'Main window handle
Global hDlgSearchReplace As Dword           'Handle of (modeless) Search/Replace dialog window
Global hDlgGoTo As Dword                    'Handle of (modeless) GoTo dialog widow
Global hDlgCompilerOutput As Dword          'Handle of (modeless) Compiler Output dialog widow
Global hDlgEditorHelp As Dword              'Handle of (modeless) Editor help dialog widow
Global hWndScintilla As Dword               'Handle of the Scintilla edit control (child of hWndMain)
Global pSciWndData As Dword                 'Scintilla Window Data pointer retrieved by SCI_GETDIRECTPOINTER message (for function SendScintillaMsg)
Global szBuffer As Asciiz*%MAX_PATH         'For temp usage (MAX_PATH=260)
Global szEditorFile As Asciiz*%MAX_PATH     'Path+Filename of the editor
Global szEditorDir As Asciiz*%MAX_PATH      'Directory path of the Editor (ending "\")
Global szIniFile As Asciiz*%MAX_PATH        'Filename of the *.ini file to store program settings
Global szCurFile As Asciiz*%MAX_PATH        'Current filename. Is "" if no or new file
Global szCurDir As Asciiz*%MAX_PATH         'Current working directory (ending "\"). Got from szCurFile but not set to "" after creating new file
Global szTemplateDir As Asciiz*%MAX_PATH    'Template directory path (for *.bas files to use as template for new files)
Global szIncDir As Asciiz*%MAX_PATH         'Include directory path (for *.inc files with API declarations and so on)
Global szCompilerFile As Asciiz*%MAX_PATH   'Filename of the Basic compiler
Global szResEditFile As Asciiz*%MAX_PATH    'Filename of the Resource editor (best: Borland Resource Workshop or the Borland C IDE)
Global szPbResToolFile As Asciiz*%MAX_PATH  'Filename of the PowerBasic Resource converter tool
Global szBasicHelpFile As Asciiz*%MAX_PATH  'Filename of the Basic help file
Global szApiHelpFile As Asciiz*%MAX_PATH    'Filename of the API help file
Global szBasicKeywordFile As Asciiz*%MAX_PATH    'Filename of the PowerBasic keyword list file
Global szApiKeywordFile As Asciiz*%MAX_PATH      'Filename of the API keyword list file
Global szConstantKeywordFile As Asciiz*%MAX_PATH 'Filename of the Constant keyword list file
Global sLoadFltTxt As String                'File filter for GetOpenFileName
Global sSaveFltTxt As String                'File filter for GetSaveFileName
Global sBasicKeyWords As String             'Basic keyword list for syntax coloring and context help
Global sApiKeyWords As String               'API keyword list for syntax coloring
Global sConstantKeyWords As String          'Constant keyword list for syntax coloring (not needed for PowerBasic)
Global sBasicKeyWordsLCase As String        'Lowercase keyword list for faster search
Global sApiKeyWordsLCase As String          'Lowercase keyword list for faster search
Global sConstantKeyWordsLCase As String     'Lowercase keyword list for faster search
Global sBuffer As String                    'For Temp usage
Global MainWinRect As Rect                  'Stores the position of the main window
Global SrchWinRect As Rect                  'Stores the position of the "Search/Replace" dialog box (only position is used, not width and height)
Global GoToWinRect As Rect                  'Stores the position of the "GoTo" dialog box (only position is used, not width and height)
Global sLastSearchKeyword As String         'Last used Search keyword
Global sLastReplaceKeyword As String        'Last used Replace keyword
Global UserColor() As Dword                 'Stores the User-selected Syntax Colors, DIMed in WinMain()
Global dwUserFontSize As Dword              'Stores the User-selected font size
Global szUserFont As Asciiz*255             'Stores the User-selected font size
Global sFileInformationString As String     'File information string for restoring caret position and sub toggle states after reloading from file
Global fAutoIndent As Long                  '%True: Auto indention enabled, False: not enabled
Global fAutoCaseCorrection As Long          '%True: Auto case correction while typing enabled, False: not enabled
Global dwCompileTimeout As Dword            'Time in sec. the editor max. waits for end of compiling (stored in ini file)
Global dwCompilerType As Dword              'Compiler type, %CMPTYPE_ constant (%CMPTYPE_POWERBASIC, %CMPTYPE_FREEBASIC...)
'
Type T_RESINFO                              'Stores resource information global for RTF resource streamed in (for the program help)
  hRes As Long                              'Resource handle of the user-defined resource containing the RTF file
  lStartAdr As Long                         'Start address of the RTF file in memory
  lEndAdr As Long                           'End address of the RTF file in memory
  lTargetPageId As Long                     'ID of the RTF page to show (>=1 because 0 is the RTF header)
  lCurPageId As Long                        'Current RTF page ID, incremented by the streaming function, must be 0 initially
End Type
Global ResInfo As T_RESINFO
Type T_PROJECTSETTINGS                      'Stores the settings for the current project
  dwTargetFileType As Dword                 'Target file type (console exe, gui exe, dll and so on), %TARGET_... ID
  szResFile As Asciiz*%MAX_PATH             'Resource file (*.res). Must be empty if not used.
  szTargetFilename As Asciiz*%MAX_PATH      'Target filename. Must be empty if not specified.
End Type
Global ProjectSettings As T_PROJECTSETTINGS
'
Declare Sub InitScintillaWindow(ByVal hWndParent As Dword)
Declare Sub LoadKeywordList(ByVal hWndParent As Dword)
Declare Sub AutoIndent()
Declare Function LoadFile(ByVal dwOpenMode As Dword) As Dword
Declare Function SaveFile() As Dword
Declare Function SaveRtfFile(szFileName As Asciiz) As Dword
Declare Function SaveFileAs() As Dword
Declare Sub CheckMarginWidth()
Declare Sub SetUserFont()
Declare Sub ExpandLine(CurLine As Dword,ByVal doExpand As Byte,ByVal force As Byte,ByVal visLevels As Long,ByVal level As Long)
Declare Sub ToggleSub(ByVal LineNumber As Long)
Declare Sub ProcessListingSettings()
Declare Sub ToggleSubsBelow(ByVal LineNumber As Long)
Declare Sub MakeTextRangeVisible(ByVal dwStartPos As Dword,ByVal dwEndPos As Dword)
Declare Sub BlockComment(ByVal Amount As Long)
Declare Sub BlockIndent(ByVal Amount As Long)
Declare Function GetCurrentLine() As Dword
Declare Function GetCurResFile(szResFile As Asciiz) As Dword
Declare Function CreateEmptyResFile(szResFileName As Asciiz) As Dword
Declare Function GetCurrentKeyWordForHelp(szBuffer As Asciiz) As Dword
Declare Sub AutoCaseCorrector()
Declare Function CodeFormatterChangeCase(ByVal lDoBas As Long,ByVal lDoApi As Long,ByVal lDoConst As Long) As Dword
Declare Function GetCurExeFile(szExeFile As Asciiz) As Dword
Declare Function SelectFileToControl(ByVal hDlg As Dword,ByVal idControl As Dword,ByVal sFilter As String,ByVal sDefaultDir As String) As Dword
Declare Function CompileFreeBasic(ByVal dwMode As Dword) As Dword
Declare Function CompilePowerBasic(ByVal dwMode As Dword) As Dword
Declare Function TyToFind(szFileToFind As Asciiz,szFileFound As Asciiz,ByVal fSearchUpperDirs As Long) As Dword
Declare Function HelpProc(ByVal hDlg As Long, ByVal wMsg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Sub AboutApp(ByVal hWndParent As Dword)
'Declare Function GetModuleFileNameEx LIB "KERNEL32.DLL" ALIAS "GetModuleFileNameExA" (ByVal hProcess As Dword,ByVal hModule As Dword,lpFileName As Asciiz,ByVal nSize AS Dword) As Dword
'*************************************************************************************************************************************
Function WinMain(ByVal hCurInstance As Dword,ByVal hPrevInstance As Dword,ByVal pszWCmdLine As WStringZ Ptr,ByVal nCmdShow As Long) As Long
  Local szClassName As Asciiz*64,wClass As WndClassEx,hFile As Dword,dwTemp As Dword,szBuffer As Asciiz*%MAX_PATH
  Static Msg As tagMsg,hAccTable As Dword,hMenuMain As Dword,MainMenuInfo As MENUITEMINFO
  'The user-selected Syntax Colors for syntax coloring we store in the global array UserColor():
  Dim UserColor(0 To 14)    'We have currently 11 colors defined from %SCE_B_DEFAULT=0 to %SCE_B_ASM=14
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  hInst=hCurInstance
  '
  GetModuleFileName hInst,szEditorFile,%MAX_PATH
  GetFullPathName Mid$(szEditorFile,InStr(-1,szEditorFile,"\")+1),SizeOf(szBuffer),szBuffer,dwTemp  'Convert to case sensitive name
  If UCase$(szBuffer)=UCase$(szEditorFile) Then szEditorFile=szBuffer   'Only if conversion successfull (!!!)
  szEditorDir=Left$(szEditorFile,InStr(-1,szEditorFile,"\"))            'Example: "C:\PROGRAMS\PB\" (ending "\")
  szIniFile=Left$(szEditorFile,InStr(-1,szEditorFile,"."))+"ini"        'The ini file has same prefix name as the executable
  sLoadFltTxt="Basic files"+$NUL+"*.BAS"+$NUL+"Include files"+$NUL+"*.INC;*.BI"+$NUL+"All files (*.*)"+$NUL+"*.*"+$NUL+$NUL 'File filter for GetOpenFilename
  sSaveFltTxt="Basic file"+$NUL+"*.BAS"+$NUL+"Include file"+$NUL+"*.INC;*.BI"+$NUL+"RTF text file"+$NUL+"*.RTF"+$NUL+"All files (*.*)"+$NUL+"*.*"+$NUL+$NUL 'File filter for GetSaveFileName
  '
  'Get the user settings from ini file:
  If @pszWCmdLine="" Then        'If no filename and no command line switch is given by the command line
    GetPrivateProfileString $PATH,$LASTFILE,"",szCurFile,SizeOf(szCurFile),szIniFile
  ElseIf @pszWCmdLine="/e" Then 'Command line switch "/e": Start with empty window
    szCurFile=""
  Else
    szCurFile=@pszWCmdLine
    If Left$(szCurFile,1)=$DQ Then szCurFile=Mid$(szCurFile,2) 'Remove starting "
    If Right$(szCurFile,1)=$DQ Then szCurFile=Left$(szCurFile,Len(szCurFile)-1) 'Remove ending "
  End If
  szCurDir=Left$(szCurFile,InStr(-1,szCurFile,"\"))
  If szCurDir="" Then szCurDir=szEditorDir
  '
  GetPrivateProfileString $PATH,$COMPILERFILE,"",szCompilerFile,SizeOf(szCompilerFile),szIniFile
  If szCompilerFile="" Then 
    If TyToFind("fbc.exe",szCompilerFile,%FALSE)=%TRUE Then 'Empty string: Try to find the file
      WritePrivateProfileString $PATH,$PBRESTOOLFILE,szPbResToolFile,szIniFile
      dwCompilerType=%CMPTYPE_FREEBASIC
      szBuffer=LTrim$(Str$(dwCompilerType))
      WritePrivateProfileString $OTHERSETTINGS,$COMPILERTYPE,szBuffer,szIniFile
    ElseIf TyToFind("pbwin.exe",szCompilerFile,%FALSE)=%TRUE Then  'Search PowerBasic/Win
      WritePrivateProfileString $PATH,$PBRESTOOLFILE,szPbResToolFile,szIniFile
      dwCompilerType=%CMPTYPE_POWERBASIC
      szBuffer=LTrim$(Str$(dwCompilerType))
      WritePrivateProfileString $OTHERSETTINGS,$COMPILERTYPE,szBuffer,szIniFile
    ElseIf TyToFind("pbcc.exe",szCompilerFile,%FALSE)=%TRUE Then  'Search PowerBasic/Win
      WritePrivateProfileString $PATH,$PBRESTOOLFILE,szPbResToolFile,szIniFile
      dwCompilerType=%CMPTYPE_POWERBASIC
      szBuffer=LTrim$(Str$(dwCompilerType))
      WritePrivateProfileString $OTHERSETTINGS,$COMPILERTYPE,szBuffer,szIniFile
    End If
  End If
  dwCompilerType=GetPrivateProfileInt($OTHERSETTINGS,$COMPILERTYPE,%CMPTYPE_FREEBASIC,szIniFile)
  If dwCompilerType>=%CMPTYPE_UNKNOWN Then dwCompilerType=%CMPTYPE_FREEBASIC
  GetPrivateProfileString $PATH,$INCLUDEDIR,szEditorDir,szIncDir,SizeOf(szIncDir),szIniFile
  If szIncDir=szEditorDir Then 
    If dwCompilerType=%CMPTYPE_POWERBASIC Then
      If TyToFind("WINAPI",szIncDir,%TRUE)=%TRUE Then  'PowerBasic
        szIncDir=szIncDir+"\"
        WritePrivateProfileString $PATH,$INCLUDEDIR,szIncDir,szIniFile
      End If
    Else                                          'FreeBasic
      If TyToFind("INC",szIncDir,%TRUE)=%TRUE Then 'Empty string: Try to find the file
        szIncDir=szIncDir+"\"
        WritePrivateProfileString $PATH,$INCLUDEDIR,szIncDir,szIniFile
      ElseIf TyToFind("INCLUDE",szIncDir,%TRUE)=%TRUE Then
        szIncDir=szIncDir+"\"
        WritePrivateProfileString $PATH,$INCLUDEDIR,szIncDir,szIniFile
      End If
    End If
  End If
  GetPrivateProfileString $PATH,$TEMPLATEDIR,szEditorDir,szTemplateDir,SizeOf(szTemplateDir),szIniFile
  GetPrivateProfileString $PATH,$APIHELPFILE,"",szApiHelpFile,SizeOf(szApiHelpFile),szIniFile
  GetPrivateProfileString $PATH,$BASICHELPFILE,"",szBasicHelpFile,SizeOf(szBasicHelpFile),szIniFile
  If (dwCompilerType=%CMPTYPE_POWERBASIC) And (szBasicHelpFile="") Then
    If TyToFind("pbwin.hlp",szBasicHelpFile,%TRUE)=%TRUE Then 'Empty string: Try to find the file
      WritePrivateProfileString $PATH,$BASICHELPFILE,szBasicHelpFile,szIniFile
    ElseIf TyToFind("pbcc.hlp",szBasicHelpFile,%TRUE)=%TRUE Then 'Empty string: Try to find the file
      WritePrivateProfileString $PATH,$BASICHELPFILE,szBasicHelpFile,szIniFile
    End If
  End If
  GetPrivateProfileString $PATH,$PBRESTOOLFILE,"",szPbResToolFile,SizeOf(szPbResToolFile),szIniFile
  If (dwCompilerType=%CMPTYPE_POWERBASIC) And (szPbResToolFile="") Then
    If TyToFind("pbres.exe",szPbResToolFile,%TRUE)=%TRUE Then 'Empty string: Try to find the file
      WritePrivateProfileString $PATH,$PBRESTOOLFILE,szPbResToolFile,szIniFile
    End If
  End If
  GetPrivateProfileString $PATH,$RESEDITFILE,"",szResEditFile,SizeOf(szResEditFile),szIniFile
  GetPrivateProfileString $PATH,$BASICKEYWORDFILE,"",szBasicKeywordFile,SizeOf(szBasicKeywordFile),szIniFile
  GetPrivateProfileString $PATH,$APIKEYWORDFILE,"",szApiKeywordFile,SizeOf(szApiKeywordFile),szIniFile
  GetPrivateProfileString $PATH,$CONSTANTKEYWORDFILE,"",szConstantKeywordFile,SizeOf(szConstantKeywordFile),szIniFile
  '
  hFile=lopen(szBasicKeywordFile,%OF_READ)                             'Does the Basic keyword list file exist?
  If hFile=%INVALID_HANDLE_VALUE Then
    Select Case dwCompilerType
    Case %CMPTYPE_POWERBASIC
      szBasicKeywordFile=Left$(szEditorFile,InStr(-1,szEditorFile,"\"))+"PowerBasicKeywords.txt" 'Set a default filename
    Case %CMPTYPE_FREEBASIC,%CMPTYPE_UNKNOWN
      szBasicKeywordFile=Left$(szEditorFile,InStr(-1,szEditorFile,"\"))+"FreeBasicKeywords.txt" 'Set a default filename
    End Select
  Else
    lclose hFile
  End If
  hFile=lopen(szApiKeywordFile,%OF_READ)                             'Does the API keyword list file exist?
  If hFile=%INVALID_HANDLE_VALUE Then
    szApiKeywordFile=Left$(szEditorFile,InStr(-1,szEditorFile,"\"))+"ApiKeywords.txt" 'Set a default filename
  Else
    lclose hFile
  End If
  hFile=lopen(szConstantKeywordFile,%OF_READ)                             'Does the Constant keyword list file exist?
  If hFile=%INVALID_HANDLE_VALUE Then
    szConstantKeywordFile=Left$(szEditorFile,InStr(-1,szEditorFile,"\"))+"ConstantKeywords.txt" 'Set a default filename
  Else
    lclose hFile
  End If
  '  
  If GetPrivateProfileStruct($WINDOWS,$MAINWNDPOS,ByRef MainWinRect,SizeOf(MainWinRect),szIniFile)=0 Then
    MainWinRect.nLeft=20
    MainWinRect.nTop=20
    MainWinRect.nRight=600
    MainWinRect.nBottom=400
  Else
    'Possibly we must correct she stored window left upper position to prevent a position outside of the desktop:
    If MainWinRect.nLeft<0 Then MainWinRect.nLeft=0
    If MainWinRect.nLeft>GetSystemMetrics(%SM_CXSCREEN)-100 Then MainWinRect.nLeft=GetSystemMetrics(%SM_CXSCREEN)-100
    If MainWinRect.nTop<0 Then MainWinRect.nTop=0
    If MainWinRect.nTop>GetSystemMetrics(%SM_CYSCREEN)-100 Then MainWinRect.nTop=GetSystemMetrics(%SM_CYSCREEN)-100
  End If
  GetPrivateProfileStruct $WINDOWS,$SEARCHWNDPOS,ByRef SrchWinRect,SizeOf(SrchWinRect),szIniFile
  GetPrivateProfileStruct $WINDOWS,$GOTOWNDPOS,ByRef GoToWinRect,SizeOf(GoToWinRect),szIniFile
  If GetPrivateProfileStruct($WINDOWS,$SYNTAXCOLORS,ByRef UserColor(0),ArrayAttr(UserColor(),4)*ArrayAttr(UserColor(),5),szIniFile)=0 Then
    UserColor(%SCE_B_DEFAULT)=RGB(0,0,0)         '%SCE_B_DEFAULT=0,       Default: RGB(00,0,0)=black
    UserColor(%SCE_B_COMMENT)=RGB(128,128,128)   '%SCE_B_COMMENT=1,       Default: RGB(128,128,128)=dark gray
    UserColor(%SCE_B_NUMBER)=RGB(0,0,255)        '%SCE_B_NUMBER=2,        Default: RGB(0,0,255)=blue
    UserColor(%SCE_B_APIKEYWORD)=RGB(128,0,0)    'SCE_B_APIKEYWORD=3,     Default: RGB(128,0,0)=dark red
    UserColor(%SCE_B_STRING)=RGB(0,128,0)        '%SCE_B_STRING=4,        Default: RGB(0,128,0)=dark green
    UserColor(%SCE_B_PREPROCESSOR)=0             '%SCE_B_PREPROCESSOR=5,  VB lexer only in original Scintilla, unsupported by the PB lexer
    UserColor(%SCE_B_OPERATOR)=RGB(0,0,0)        '%SCE_B_OPERATOR=6,      Default: RGB(0,0,0)=black
    UserColor(%SCE_B_IDENTIFIER)=RGB(0,0,0)      '%SCE_B_IDENTIFIER=7,    internaly set to the color of %SCE_B_DEFAULT
    UserColor(%SCE_B_DATE)=0                     '%SCE_B_DATE=8,          VB lexer only, unsupported by the PB lexer
    UserColor(%SCE_B_STRINGEOL)=RGB(128,0,128)   '%SCE_B_STRINGEOL=9,     VB lexer only, unsupported by the PB lexer, formerly %SCE_B_CONSTANT
    UserColor(%SCE_B_BASICKEYWORD)=RGB(128,64,0) '%SCE_B_BASICKEYWORD=10, PB/FB lexer: Basic keyword (same as SCE_B_KEYWORD2)
    UserColor(%SCE_B_KEYWORD3)=0                 '%SCE_B_KEYWORD3=11,     VB lexer only, unsupported by the PB lexer
    UserColor(%SCE_B_KEYWORD4)=0                 '%SCE_B_KEYWORD4=12,     VB lexer only, unsupported by the PB lexer
    UserColor(%SCE_B_CONSTANT)=RGB(128,0,128)    '%SCE_B_CONSTANT=13,     Default: RGB(128,0,128)=violett, PB lexer only, usupported by the VB lexer
    UserColor(%SCE_B_ASM)=RGB(128,64,0)          '%SCE_B_ASM=14           Default: RGB(128,64,0)=brown, PB lexer only, usupported by the VB lexer
  End If
  GetPrivateProfileString $WINDOWS,$FONTNAME,"Courier New",szUserFont,SizeOf(szUserFont),szIniFile
  dwUserFontSize=GetPrivateProfileInt($WINDOWS,$FONTSIZE,9,szIniFile)
  If dwUserFontSize<4 Then dwUserFontSize=4
  If dwUserFontSize>18 Then dwUserFontSize=18
  fAutoIndent=GetPrivateProfileInt($OTHERSETTINGS,$AUTOINDENT,%TRUE,szIniFile)
  fAutoCaseCorrection=GetPrivateProfileInt($OTHERSETTINGS,$AUTOCASECORRECTION,%TRUE,szIniFile)
  szBuffer=""
  GetPrivateProfileString $WINDOWS,$SEARCHKEYWORD,"",szBuffer,SizeOf(szBuffer),szIniFile
  sLastSearchKeyword=szBuffer  'Last Search keyword
  szBuffer=""
  GetPrivateProfileString $WINDOWS,$REPLACEKEYWORD,"",szBuffer,SizeOf(szBuffer),szIniFile
  sLastReplaceKeyword=szBuffer  'Last Replace keyword
  dwCompileTimeout=GetPrivateProfileInt($OTHERSETTINGS,$COMPILETIMEOUT,10,szIniFile)  'Time in sec. the editor max. waits for end of compiling
  If dwCompileTimeout>30 Then dwCompileTimeout=30
  '
'  'Create the dialog class for the editor's help (small gimmick: with an own dialog class the "true" dialog icon is displayed)
'  szClassName           = $DLGCLASS_EDITORHELP             'Set the Help dialog's class name
'  wClass.cbSize         = SizeOf(wClass)
'  wClass.style          = %CS_VREDRAW Or %CS_HREDRAW
'  wClass.lpfnWndProc    = CodePtr(EditorHelpDlgProc)
'  wClass.cbClsExtra     = 0
'  wClass.cbWndExtra     = %DLGWINDOWEXTRA
'  wClass.hInstance      = hInst
'  wClass.hIcon          = LoadIcon(%NULL,ByVal %IDI_QUESTION)
'  wClass.hCursor        = LoadCursor(%NULL,ByVal %IDC_ARROW)
'  wClass.hbrBackground  = GetStockObject(%LTGRAY_BRUSH)
'  wClass.lpszMenuName   = %NULL
'  wClass.lpszClassName  = VarPtr(szClassName)
'  wClass.hIConSm        = %NULL  'LoadIcon(hInst, ByVal 1)
'  RegisterClassEx(wClass)    'RegisterClassEx needs NT 4.0 or later
  '
  'Now create the main window of the application:  
  szClassName           = $WNDCLASS_MAIN             'Set the Main windows's class name
  wClass.cbSize         = SizeOf(wClass)
  wClass.style          = %CS_HREDRAW Or %CS_VREDRAW
  wClass.lpfnWndProc    = CodePtr(MainWndProc)
  wClass.cbClsExtra     = 0
  wClass.cbWndExtra     = 0
  wClass.hInstance      = hInst
  wClass.hIcon          = LoadIcon(hInst,ByVal 1)
  wClass.hCursor        = LoadCursor(%NULL,ByVal %IDC_ARROW)
  wClass.hbrBackground  = GetStockObject(%WHITE_BRUSH)
  wClass.lpszMenuName   = %NULL
  wClass.lpszClassName  = VarPtr(szClassName)
  wClass.hIConSm        = %NULL  'LoadIcon(hInst, ByVal 1)
  RegisterClassEx wClass    'RegisterClassEx needs NT 4.0 or later
  '
  hMenuMain=LoadMenu(hInst,ByVal 1)
  'SetMenuItemBitmaps hMenuMain,%IDC_COMPILE,%MF_BYCOMMAND,LoadBitmap(hInst,ByVal 1),LoadBitmap(hInst,ByVal 1) 'Doesn't work in main menu
'  MainMenuInfo.cbSize=SizeOf(MainMenuInfo)
'  MainMenuInfo.fMask=%MIIM_TYPE
'  MainMenuInfo.fType =%MFT_OWNERDRAW
'  MainMenuInfo.dwTypeData=0
'  SetMenuItemInfo hMenuMain,%IDC_COMPILE,%MF_BYCOMMAND,MainMenuInfo
'  SetMenuItemInfo hMenuMain,%IDC_RUN,%MF_BYCOMMAND,MainMenuInfo
  '
  'Create the main window based on registered window class
  hWndMain=CreateWindow($WNDCLASS_MAIN,_     'window class name
           $APP_NAME,_                       'window caption
           %WS_OVERLAPPEDWINDOW,_            'window style
           MainWinRect.nLeft,_               'initial x position
           MainWinRect.nTop,_                'initial y position
           MainWinRect.nRight-MainWinRect.nLeft,_  'initial x size
           MainWinRect.nBottom-MainWinRect.nTop,_  'initial y
           %NULL,_                           'parent window handle
           hMenuMain,_                       'Menu handle
           hInst,_                           'program instance handle
           %NULL)                            'creation parameter

  ShowWindow hWndMain,nCmdShow               'displays the window on the screen
  UpdateWindow hWndMain                      'directs the window to paint itself

  'Main message loop of program:
  hAccTable=LoadAccelerators(hInst,ByVal 1)
  While GetMessage(Msg,%NULL,0,0)
    If IsDialogMessage(hDlgSearchReplace,Msg)=0 Then   'Check whether the message is for the (modeless) "Search/Replace" dialog window
      If IsDialogMessage(hDlgGoTo,Msg)=0 Then          'Check whether the message is for the (modeless) "GoTo" dialog window
        If IsDialogMessage(hDlgCompilerOutput,Msg)=0 Then   'Check whether the message is for the (modeless) "Compiler output" dialog window
          If IsDialogMessage(hDlgEditorHelp,Msg)=0 Then   'Check whether the message is for the (modeless) "Editor's help" dialog window
            If TranslateAccelerator(hWndMain,hAccTable,Msg)=0 Then
              TranslateMessage Msg
              DispatchMessage Msg
            End If
          End If
        End If
      End If
    End If
  Wend
  '
  'Finally write user settings to the ini file:
  'The return value of the first write to ini file should be determined to prevent
  'several error message boxes on write protected drives:
  If WritePrivateProfileString($PATH,$LASTFILE,szCurFile,szIniFile)<>0 Then
    WritePrivateProfileStruct $WINDOWS,$MAINWNDPOS,ByRef MainWinRect,SizeOf(MainWinRect),szIniFile
    WritePrivateProfileStruct $WINDOWS,$SEARCHWNDPOS,ByRef SrchWinRect,SizeOf(SrchWinRect),szIniFile
    WritePrivateProfileStruct $WINDOWS,$GOTOWNDPOS,ByRef GoToWinRect,SizeOf(GoToWinRect),szIniFile
    szBuffer=sLastSearchKeyword  'Last used Search keyword
    WritePrivateProfileString $WINDOWS,$SEARCHKEYWORD,szBuffer,szIniFile
    szBuffer=sLastReplaceKeyword  'Last used Replace keyword
    WritePrivateProfileString $WINDOWS,$REPLACEKEYWORD,szBuffer,szIniFile
    szBuffer=LTrim$(Str$(dwCompileTimeout))  'Time in sec. the editor max. waits for end of compiling
    WritePrivateProfileString $OTHERSETTINGS,$AUTOINDENT,LTrim$(Str$(fAutoIndent)),szIniFile
    WritePrivateProfileString $OTHERSETTINGS,$AUTOCASECORRECTION,LTrim$(Str$(fAutoCaseCorrection)),szIniFile
    WritePrivateProfileString $OTHERSETTINGS,$COMPILETIMEOUT,szBuffer,szIniFile
  End If
  '
  UnregisterClass $WNDCLASS_MAIN,hInst
  'UnregisterClass $DLGCLASS_EDITORHELP,hInst
  '
  Function=Msg.wParam                   'Clean up and assign return value
End Function
'*************************************************************************************************************************************
Function MainWndProc(ByVal hWnd As Dword,ByVal wMsg As Dword,ByVal wParam As Dword,ByVal lParam As Dword) Export As Long
  Static szBuffer As Asciiz*1024,szFileExtension As Asciiz*%MAX_PATH,pNMHdr As SCNotification Ptr,dwNumLines As Dword,i As Long
  Static hWndHelp As Dword
  'Local pMenuItemMeasure As MEASUREITEMSTRUCT Ptr,pDrawIten As DRAWITEMSTRUCT Ptr,hOldPen As Dword,hOldBrush As Dword
  '
  Select Case wMsg
  Case %WM_CREATE '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    hWndScintilla=CreateWindowEx(0,$SCINTILLA_WNDCLASS,"",%WS_CHILD Or %WS_VISIBLE Or %WS_TABSTOP,0,0,10,10,hWnd,%IDC_SCINTILLA,hInst,ByVal %NULL)
    pSciWndData=SendMessage(hWndScintilla,%SCI_GETDIRECTPOINTER,0,0) 'Window Data pointer for SendScintillaMsg(), a SendMessage replacement
    InitScintillaWindow(hWnd)  'Init the Scintilla control for PowerBasic (coloring, folding, font and so on)
    '
    If szCurFile<>"" Then PostMessage hWnd,%WM_COMMAND,%IDC_OPEN_VIRTUAL,0 'If there is a current filename open the file
    SetFocus hWndScintilla
    Function=0
  Case %WM_COMMAND '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select Case LoWrd(wParam)
    Case %IDC_SCINTILLA
      If HiWrd(wParam)=%SCEN_CHANGE Then
        If fAutoCaseCorrection=%TRUE Then AutoCaseCorrector
      End If
    Case %IDC_NEWFILE_EMPTY
      LoadFile %IDC_NEWFILE_EMPTY       'New empty file
    Case %IDC_NEWFILE_BY_TEMPLATE
      LoadFile %IDC_NEWFILE_BY_TEMPLATE 'New file by template
    Case %IDC_NEW_WINDOW                'New window
      WinExec szEditorFile+" /e",%SW_SHOW
    Case %IDC_OPEN_FILE
      LoadFile %IDC_OPEN_FILE           'Open existing file
    Case %IDC_OPEN_VIRTUAL              'Virtual control as PostMessage target, loads file without file selection box
      LoadFile %IDC_OPEN_VIRTUAL        'Open existing file
    Case %IDC_SAVE
      SaveFile
    Case %IDC_SAVE_AS
      SaveFileAs
    Case %IDC_EXIT_APP
      PostMessage hWnd,%WM_CLOSE,0,0
    Case %IDC_LASTFILE_1

    Case %IDC_LASTFILE_2

    Case %IDC_LASTFILE_3

    Case %IDC_LASTFILE_4

    Case %IDC_UNDO
      SendScintillaMsg pSciWndData,%SCI_UNDO,0,0
    Case %IDC_CUT
      SendScintillaMsg pSciWndData,%SCI_CUT,0,0
    Case %IDC_COPY
      SendScintillaMsg pSciWndData,%SCI_COPY,0,0
    Case %IDC_PASTE
      SendScintillaMsg pSciWndData,%SCI_PASTE,0,0
    Case %IDC_SELECT_ALL
      SendScintillaMsg pSciWndData,%SCI_SELECTALL,0,0
    Case %IDC_SERACH_REPLACE
      hDlgSearchReplace=CreateDialog(hInst,ByVal %IDD_SEARCH_REPLACE,hWndMain,CodePtr(SearchReplaceFunc)) 'non-modal dialog window!
    Case %IDC_GOTO_LINE
      hDlgGoTo=CreateDialog(hInst,ByVal %IDD_GOTO,hWndMain,CodePtr(GoToFunc)) 'non-modal dialog window!
    Case %IDC_TOGGLE_SUB   'Toogle the current sub/function
      ToggleSub(GetCurrentLine())
    Case %IDC_TOGGLE_ALL_SUBS
      ToggleSubsBelow(GetCurrentLine())
    Case %IDC_BLOCKCOMMENT         'Block comment
      BlockComment(1)
    Case %IDC_BLOCKUNCOMMENT       'Block uncomment
      BlockComment(-1)
    Case %IDC_BLOCKINDENT          'Block indent
      BlockIndent(1)
    Case %IDC_BLOCKUNINDENT        'Block unindent
      BlockIndent(-1)
    Case %IDC_COMPILE
      If szCurFile="" Then   'No filename specified
        If MessageBox(hWndMain,$NO_FILENAME_SAVE,$APP_NAME_SHORT,%MB_ICONSTOP Or %MB_YESNO Or %MB_DEFBUTTON1)=%IDYES Then
          SaveFileAs
        End If
      End If
      If szCurFile<>"" Then 
        If SaveFile()=0 Then
          Select Case dwCompilerType
          Case %CMPTYPE_POWERBASIC
            CompilePowerBasic 0   'Parameter 0: Compile only, don't run
          Case Else '%CMPTYPE_FREEBASIC
            CompileFreeBasic 0   'Parameter 0: Compile only, don't run
          End Select
        End If
      End If
    Case %IDC_RUN
      If szCurFile="" Then   'No filename specified
        If MessageBox(hWndMain,$NO_FILENAME_SAVE,$APP_NAME_SHORT,%MB_ICONSTOP Or %MB_YESNO Or %MB_DEFBUTTON1)=%IDYES Then
          SaveFileAs
        End If
      End If
      If szCurFile<>"" Then 
        If SaveFile()=0 Then
          Select Case dwCompilerType
          Case %CMPTYPE_POWERBASIC
            CompilePowerBasic 1   'Parameter 1: Compile and run
          Case Else '%CMPTYPE_FREEBASIC
            CompileFreeBasic 1   'Parameter 1: Compile and run
          End Select
        End If
      End If
    Case %IDC_EDIT_RES         'Start Resource editor with the current *.res/*.rc file
      If GetCurResFile(szBuffer) Then
        If InStr(szBuffer," ") Then    'If spaces in path/filename, then add double-quotes
          If WinExec(szResEditFile+" "+$DQ+szBuffer+$DQ,%SW_SHOW)<33 Then MessageBox hWndMain,"Error starting resource editor"+Chr$(13)+szResEditFile,"",%MB_ICONSTOP
        Else
          If WinExec(szResEditFile+" "+szBuffer,%SW_SHOW)<33 Then MessageBox hWndMain,"Error starting resource editor"+Chr$(13)+szResEditFile,"",%MB_ICONSTOP
        End If
      End If
    Case %IDC_UPDATE_PBRES     'Update the PowerBasic *.pbr file from *.res resource file
      If GetCurResFile(szBuffer) Then
        If InStr(szBuffer," ") Then    'If spaces in path/filename, then add double-quotes
          If WinExec(szPbResToolFile+" "+$DQ+szBuffer+$DQ,%SW_SHOWMINNOACTIVE)<33 Then MessageBox hWndMain,"Error starting PowerBasic resource converter"+Chr$(13)+szPbResToolFile,"",%MB_ICONSTOP
        Else
          If WinExec(szPbResToolFile+" "+szBuffer,%SW_SHOWMINNOACTIVE)<33 Then MessageBox hWndMain,"Error starting PowerBasic resource converter"+Chr$(13)+szPbResToolFile,"",%MB_ICONSTOP
        End If
      End If
    Case %IDC_CODECORRECTOR
      DialogBox hInst,ByVal %IDD_CODEFORMATTERDLG,hWndMain,CodePtr(CodeFormatterDlgFunc)
    Case %IDC_FONT_SETTINGS
      If DialogBox(hInst,ByVal %IDD_FONTDLG,hWndMain,CodePtr(FontDlgFunc))=1 Then SetUserFont() 'If closed with "OK" update font settings
    Case %IDC_GENERAL_SETTINGS
      DialogBox hInst,ByVal %IDD_GENSETTINGSDLG,hWndMain,CodePtr(GeneralSettingsDlgFunc)
    Case %IDC_PROJECT_SETTINGS     'Settings for teh current project
      DialogBox hInst,ByVal %IDD_PROJECTSETTINGSDLG,hWndMain,CodePtr(ProjectSettingsDlgFunc)
    Case %IDC_AUTOINDENT
      If fAutoIndent=%TRUE Then fAutoIndent=%FALSE Else fAutoIndent=%TRUE
    Case %IDC_AUTOCASECORRECTION
      If fAutoCaseCorrection=%TRUE Then fAutoCaseCorrection=%FALSE Else fAutoCaseCorrection=%TRUE
    Case %IDC_HELP_KEYWORD
      If GetCurrentKeyWordForHelp(szBuffer)=0 Then 'If the current keyword retrieved into szBuffer is no Basic keyword, let's assume it's an API keyword
        If UCase$(Right$(szApiHelpFile,4))=".HLP" Then
          WinHelp hWndMain,szApiHelpFile,%HELP_PARTIALKEY,ByRef szBuffer
        Else
          HtmlHelp %NULL,szApiHelpFile,%HH_DISPLAY_INDEX,ByRef szBuffer
        End If
      Else 'keyword in szBuffer is a Basic keyword
        szFileExtension=UCase$(Right$(szBasicHelpFile,4))   'Used file extension
        If szFileExtension=".HLP" Then                         'WinHelp
          If dwCompilerType=%CMPTYPE_POWERBASIC Then WinHelp hWndMain,szBasicHelpFile,%HELP_PARTIALKEY,ByRef szBuffer  'YES!!!!!, call it 2 times! (opens selection box for multi keawords if necassary)
          'Note: Some PowerBasic keywords such as "mid$","#BLOAT","#DEBUG" don't work with a single call of WinHelp
          WinHelp hWndMain,szBasicHelpFile,%HELP_PARTIALKEY,ByRef szBuffer
        ElseIf szFileExtension=".CHM" Or szFileExtension=".COL" Then  'HTML help
          HtmlHelp hWndMain,szBasicHelpFile,%HH_DISPLAY_INDEX,ByRef szBuffer
        ElseIf szFileExtension=".EXE" Then                     'EXE: Gets the keyword as command line parameter
          ShellExecute hWndMain,"open",szBasicHelpFile,szBuffer,"",%SW_SHOWNORMAL
        Else
          ShellExecute hWndMain,"open",szBasicHelpFile,"","",%SW_SHOWNORMAL
        End If
      End If
    Case %IDC_HELP_BASIC
      If UCase$(Right$(szBasicHelpFile,4))=".HLP" Then
        WinHelp hWndMain,szBasicHelpFile,%HELP_CONTENTS,0
      Else
        HtmlHelp hWndMain,szBasicHelpFile,%HH_DISPLAY_INDEX,ByVal 0  'WinExec "HH.EXE "+szApiHelpFile,%SW_SHOW
      End If
    Case %IDC_HELP_API
      szFileExtension=UCase$(Right$(szApiHelpFile,4))   'Used file extension
      If szFileExtension=".HLP" Then                         'WinHelp
        WinHelp hWndMain,szApiHelpFile,%HELP_CONTENTS,0
      ElseIf szFileExtension=".CHM" Or szFileExtension=".COL" Then  'HTML help
        HtmlHelp hWndMain,szApiHelpFile,%HH_DISPLAY_INDEX,ByVal 0  'WinExec "HH.EXE "+szApiHelpFile,%SW_SHOW
      Else
        ShellExecute hWndMain,"open",szApiHelpFile,"","",%SW_SHOWNORMAL
      End If
    Case %IDC_HELP_EDITOR
      If LoadLibrary("RICHED32")=%NULL Then 'Richedit 1.0 (Richedit 2.0 "RICHED20" isn't necessary and above EN_UPDATE cant't be switched out)
        MessageBox hWnd,"Can't open help."+$CR+"Unable to load riched32.dll","",%MB_ICONSTOP
      Else
        hDlgEditorHelp=CreateDialog(hInst,ByVal %IDD_EDITORHELP,0,CodePtr(EditorHelpDlgProc)) 'if standard dialog class used (no parent window!)
        'hDlgEditorHelp=CreateDialog(hInst,ByVal %IDD_EDITORHELP,0,%NULL) 'if user-defined dialog class used (no parent window!)
      End If
    Case %IDC_HELP_ABOUT
      AboutApp hWnd
    End Select
    Function=0
  Case %WM_TIMER '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    'WM_TIMER with Id 1 is sent after loading a new file with a file information string. This string contains information
    'about caret position, toggle states of the subs/functions and project settings of the loaded file.
    'The timer is used to give the lexer enough time for processing the entire (new) file before we can toggle the subs.
    KillTimer hWnd,1
    ProcessListingSettings()
  Case %WM_NOTIFY '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    pNMHdr=lParam                'Init the SCNotification structure pointer
    Select Case @pNMHdr.NotifyHeader.code 'Select the SCN_... notification message
    Case %SCN_MARGINCLICK        'Mouse click at margin
      If @pNMHdr.margin=1 Then ToggleSub(SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,@pNMHdr.position,0)) 'Margin 1: Toggle
    Case %SCN_MODIFIED           'Got by SCI_SETMODEVENTMASK with the flags %SC_MOD_INSERTTEXT and %SC_MOD_DELETETEXT set
      If @pNMHdr.linesAdded Then CheckMarginWidth() 'If lines added/removed then change margin width if necessary
    Case %SCN_NEEDSHOWN          'One or more lines are currently invisible and should be made visible
      MakeTextRangeVisible(@pNMHdr.position,@pNMHdr.position+@pNMHdr.length)
    Case %SCN_CHARADDED          'Character added
      If @pNMHdr.ch=&H0A Or @pNMHdr.ch=&H0D Then   'If Carriage or Linefeed
        If fAutoCaseCorrection=%TRUE Then AutoCaseCorrector
        If fAutoIndent=%TRUE Then AutoIndent
      End If
    Case %SCN_UPDATEUI 'Text or styling or selection changed (SCN_PAINTED and SCN_UPDATEUI are usefull, but SCN_PAINTED is fired very often)
      If fAutoCaseCorrection=%TRUE Then AutoCaseCorrector
    End Select
  Case %WM_INITMENUPOPUP '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    Select Case LoWrd(LParam)
    Case 0 'Menu "File"
      If szCurFile="" Or SendScintillaMsg(pSciWndData,%SCI_GETMODIFY,0,0)=0 Then 'No filename or saving not necessary: Gray menu entry "Save"
        EnableMenuItem wParam,%IDC_SAVE,%MF_BYCOMMAND Or %MF_GRAYED
      Else
        EnableMenuItem wParam,%IDC_SAVE,%MF_BYCOMMAND Or %MF_ENABLED
      End If
    Case 1 'Menu "Edit"
      If IsClipboardFormatAvailable(%CF_TEXT) Then  'Gray Menu entry "Paste" if there is no text in clipboard
        EnableMenuItem wParam,%IDC_PASTE,%MF_BYCOMMAND Or %MF_ENABLED
      Else
        EnableMenuItem wParam,%IDC_PASTE,%MF_BYCOMMAND Or %MF_GRAYED
      End If
    'Case 2,3 'Menu entries "Compile" and "Run"
    Case 4 'Menu "Tools"
      If szCurFile="" Then   'No filename specified: Gray menu entries "Compile","Run","Edit resources","Update PB resources"
        EnableMenuItem wParam,%IDC_EDIT_RES,%MF_BYCOMMAND Or %MF_GRAYED
        EnableMenuItem wParam,%IDC_UPDATE_PBRES,%MF_BYCOMMAND Or %MF_GRAYED
      Else
        EnableMenuItem wParam,%IDC_EDIT_RES,%MF_BYCOMMAND Or %MF_ENABLED
        If dwCompilerType=%CMPTYPE_POWERBASIC Then
          EnableMenuItem wParam,%IDC_UPDATE_PBRES,%MF_BYCOMMAND Or %MF_ENABLED
        Else
          EnableMenuItem wParam,%IDC_UPDATE_PBRES,%MF_BYCOMMAND Or %MF_GRAYED
        End If
      End If
    Case 5 'Menu "Options"
      If fAutoIndent=%TRUE Then
        CheckMenuItem wParam,%IDC_AUTOINDENT,%MF_BYCOMMAND Or %MF_CHECKED
      Else
        CheckMenuItem wParam,%IDC_AUTOINDENT,%MF_BYCOMMAND Or %MF_UNCHECKED
      End If
      If fAutoCaseCorrection=%TRUE Then
        CheckMenuItem wParam,%IDC_AUTOCASECORRECTION,%MF_BYCOMMAND Or %MF_CHECKED
      Else
        CheckMenuItem wParam,%IDC_AUTOCASECORRECTION,%MF_BYCOMMAND Or %MF_UNCHECKED
      End If
      If dwCompilerType=%CMPTYPE_POWERBASIC Then
        EnableMenuItem wParam,%IDC_PROJECT_SETTINGS,%MF_BYCOMMAND Or %MF_GRAYED
      Else
        EnableMenuItem wParam,%IDC_PROJECT_SETTINGS,%MF_BYCOMMAND Or %MF_ENABLED
      End If
    Case 6 'Menu "Help"
    End Select
'  Case %WM_MEASUREITEM '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
'    If wParam=0 Then 'Measures of the ownerdraw menu items Compile and Run (%IDC_COMPILE and %IDC_RUN)
'      pMenuItemMeasure=lParam  'Get the MEASUREITEMSTRUCT 
'      '@pMenuItemMeasure.CtlType=%ODT_MENU
'      '@pMenuItemMeasure.CtlID=0
'      If @pMenuItemMeasure.itemID=%IDC_COMPILE Then
'        @pMenuItemMeasure.itemWidth=30
'        @pMenuItemMeasure.itemHeight=12   
'      ElseIf @pMenuItemMeasure.itemID=%IDC_RUN Then
'        @pMenuItemMeasure.itemWidth=30
'        @pMenuItemMeasure.itemHeight=12   
'      End If
'      '@pMenuItemMeasure.itemData=0
'    End If
'  Case %WM_DRAWITEM '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'    If wParam=0 Then 'Message comes from the ownerdraw menu items Compile and Run (%IDC_COMPILE and %IDC_RUN)
'      pDrawIten=lParam 'DRAWITEMSTRUCT
'      'hOldPen=SelectObject(@pDrawIten.hDC,GetStockObject(%NULL_PEN))
'      hOldBrush=SelectObject(@pDrawIten.hDC,GetStockObject(%NULL_BRUSH))
'      Rectangle @pDrawIten.hDC,@pDrawIten.rcItem.nLeft,@pDrawIten.rcItem.nTop,@pDrawIten.rcItem.nRight,@pDrawIten.rcItem.nBottom
'      Select Case @pDrawIten.itemID
'      Case %IDC_COMPILE
'        DrawText @pDrawIten.hDC,"&Compile",8,@pDrawIten.rcItem,%DT_SINGLELINE Or %DT_CENTER Or %DT_VCENTER
'      Case %IDC_RUN
'        DrawText @pDrawIten.hDC,"&Run",4,@pDrawIten.rcItem,%DT_SINGLELINE Or %DT_CENTER Or %DT_VCENTER
'      End Select
'      'SelectObject @pDrawIten.hDC,hOldPen
'      SelectObject @pDrawIten.hDC,hOldBrush
'    End If
  Case %WM_SIZE '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
    MoveWindow hwndScintilla,0,0,LoWrd(lParam),HiWrd(lParam),%TRUE 'Fit the Scintilla control into the main window
    Function=0
  Case %WM_SETFOCUS '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SetFocus hwndScintilla
    Function=0
  Case %WM_CLOSE   '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    If SendScintillaMsg(pSciWndData,%SCI_GETMODIFY,0,0)<>0 Then
      Select Case MessageBox(hWndMain,$TEXT_IS_CHANGED+Chr$(13)+$TEXT_CHANGE_IT,$APP_NAME_SHORT,%MB_ICONSTOP Or %MB_YESNOCANCEL Or %MB_DEFBUTTON1)
      Case %IDYES
        If szCurFile="" Then 'No filename
          SaveFileAs
        Else
          SaveFile
        End If
        Function=DefWindowProc(hWnd,wMsg,wParam,lParam) 'Close the window
      Case %IDNO
        Function=DefWindowProc(hWnd,wMsg,wParam,lParam) 'Close the window
      Case %IDCANCEL
        Function=0                                      'Don't close the window
      End Select
    Else
      Function=DefWindowProc(hWnd,wMsg,wParam,lParam)   'Close the window
    End If
  Case %WM_DESTROY '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    GetWindowRect hWndMain,MainWinRect              'We store the last window dimensions in ini file
    WinHelp hWndMain,szBasicHelpFile,%HELP_QUIT,0
    'WinHelp hWndMain,szEditorHelpFile,%HELP_QUIT,0
    If UCase$(Right$(szApiHelpFile,4))=".HLP" Then
      WinHelp hWndMain,szApiHelpFile,%HELP_QUIT,0
    Else
      HtmlHelp hWndMain,szApiHelpFile,%HH_CLOSE_ALL,ByVal 0
    End If
    '
    PostQuitMessage 0                 'inserts "quit" message into message queue
    Function=0
  Case Else '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Function=DefWindowProc(hWnd,wMsg,wParam,lParam)     'performs default processing of message
  End Select
End Function
'*************************************************************************************************************************************
Function TyToFind(szFileToFind As Asciiz,szFileFound As Asciiz,ByVal fSearchUpperDirs As Long) As Dword
  'Searches the current directory and all sub directories for the file and returns the full path if found.
  'If fSearchUpperDirs the search is extended to oen directory level higher.
  'The function searches only in the editor's directory, it's sub-directory one level deeper, the directories at the same
  'level and one directory higher (otherwise the search could need too much time).
  'If not successfull the output string is empty and the function returns FALSE.
  'Used global variables: szEditorDir (Example: "C:\PROGRAMS\PB\" (ending "\"))
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static FindData As WIN32_FIND_DATA,FindData2 As WIN32_FIND_DATA,hSearch As Dword,hSearch2 As Dword
  Static dwTemp As Dword,dwRetVal As Dword,szCurDir As Asciiz*%MAX_PATH,szCurDir2 As Asciiz*%MAX_PATH
  Static szEditorDirWithoutPath As Asciiz*%MAX_PATH
  '
  dwRetVal=%TRUE  'Set function return value to "success" initially
  szFileFound=""  'Empty the output string
  '
  dwTemp=InStr(szFileToFind,"\")                           'Path information in?
  If dwTemp Then szFileToFind=Mid$(szFileToFind,dwTemp+1)  'Remove path
  '
  'First: Search the editor's directory and it's sub directories:
  szCurDir=szEditorDir
  hSearch=FindFirstFile(szCurDir+"*.*",FindData)
  If hSearch<>%INVALID_HANDLE_VALUE Then
    Do
      If (FindData.dwFileAttributes And %FILE_ATTRIBUTE_DIRECTORY) Then
        If FindData.cFileName<>"." And FindData.cFileName<>".." Then
          If UCase$(FindData.cFileName)=UCase$(szFileToFind) Then   'Directory found in the current sub directory
            szFileFound=szEditorDir+FindData.cFileName
            Exit
          End If
          szCurDir=szEditorDir+FindData.cFileName+"\"
          hSearch2=FindFirstFile(szCurDir+"*.*",FindData2)
          Do
            If UCase$(FindData2.cFileName)=UCase$(szFileToFind) Then   'File found in the current sub directory
              szFileFound=szCurDir+FindData2.cFileName
              FindClose hSearch2
              Exit, Exit                              'Exit both loops
            End If
          Loop While FindNextFile(hSearch2,FindData2)
          FindClose hSearch2
        End If    'FindData.cFileName<>"." And FindData.cFileName<>".."
      Else
        If UCase$(FindData.cFileName)=UCase$(szFileToFind) Then   'File or directory found in the current sub directory
          szFileFound=szEditorDir+FindData.cFileName
          Exit Loop
        End If
      End If      '(FindData.dwFileAttributes And %FILE_ATTRIBUTE_DIRECTORY)
    Loop While FindNextFile(hSearch,FindData)
    FindClose hSearch
  End If
  If Len(szFileFound) Then GoTo DoneTyToFind
  '
  If fSearchUpperDirs=%FALSE Then
    dwRetVal=%FALSE  'If we reach this the search wasn't successfull
    GoTo DoneTyToFind
  End If
  '
  'Second: Search the directories above the editor's directory and the directories at the same level:
  szCurDir=szEditorDir
  szCurDir=Left$(szCurDir,Len(szCurDir)-1)  'Remove the trailing Backslash (remember: szEditorDir has *always* a trailing Backslash)
  szCurDir=Left$(szCurDir,InStr(-1,szCurDir,"\"))  'The next upper directory, path with trailing Backslash
  hSearch=FindFirstFile(szCurDir+"*.*",FindData)
  If hSearch<>%INVALID_HANDLE_VALUE Then
    Do
      If (FindData.dwFileAttributes And %FILE_ATTRIBUTE_DIRECTORY) Then
        If FindData.cFileName<>"." And FindData.cFileName<>".." Then
          If UCase$(FindData.cFileName)=UCase$(szFileToFind) Then   'Directory found in the current sub directory
            szFileFound=szCurDir+FindData.cFileName
            Exit
          End If
          szCurDir2=szCurDir+FindData.cFileName+"\"
          hSearch2=FindFirstFile(szCurDir2+"*.*",FindData2)
          Do
            If UCase$(FindData2.cFileName)=UCase$(szFileToFind) Then   'File or directory found in the current sub directory
              szFileFound=szCurDir2+FindData2.cFileName
              FindClose hSearch2
              Exit, Exit                              'Exit both loops
            End If
          Loop While FindNextFile(hSearch2,FindData2)
          FindClose hSearch2
        End If    'FindData.cFileName<>"." And FindData.cFileName<>".."
      Else 
        If UCase$(FindData.cFileName)=UCase$(szFileToFind) Then   'File found in the current sub directory
          szFileFound=szCurDir+FindData.cFileName
          Exit Loop
        End If
      End If      '(FindData.dwFileAttributes And %FILE_ATTRIBUTE_DIRECTORY)
    Loop While FindNextFile(hSearch,FindData)
    FindClose hSearch
  End If
  If Len(szFileFound) Then GoTo DoneTyToFind
  '
  dwRetVal=%FALSE  'If we reach this the search wasn't successfull
  DoneTyToFind:
  'MsgBox szFileFound
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Sub InitScintillaWindow(ByVal hWndParent As Dword)
  'Initializes the Scintilla Edit window for PowerBasic editing (keyword coloring, folding and so on)
  'Used global variables: hWndMain,hInst,hWndScintilla,pSciWndData
  Static szBuffer As Asciiz*256,szBuffer2 As Asciiz*256
  '
  'Now we can set different styles for the different cases if we want (but here we need one style only).
  'Set the default style:
  SetUserFont  'In this sub we set the different syntax colors and the user-selected font
  '
  'Init folding of SUBs/FUNCTIONs:
  szBuffer="fold"
  szBuffer2="1"
  SendScintillaMsg pSciWndData,%SCI_SETPROPERTY,ByRef szBuffer,ByRef szBuffer2      'Enable folding (toggling subs/functions)
  '
  'Config margin 1 (line numbers):
  SendScintillaMsg pSciWndData,%SCI_SETMARGINTYPEN,1,%SC_MARGIN_NUMBER              'Margin 1 (line numbers): Set format
  SendScintillaMsg pSciWndData,%SCI_SETMARGINMASKN,1,0                              'Margin 1: No folder symbols
  SendScintillaMsg pSciWndData,%SCI_SETMARGINSENSITIVEN,1,1                         'Margin 1: Send WM_NOTIFY after mouse clicks
  'SendScintillaMsg pSciWndData,%SCI_SETMARGINWIDTHN,1,20                            'Margin 1: Set width (enough for 99999 lines)
  CheckMarginWidth                                                                  'Set margin width depending on the number of lines

  'Config margin 2 (symbol for closed subs):
  SendScintillaMsg pSciWndData,%SCI_SETMARGINWIDTHN,2,10                            'Margin 0 (Folder margin): Set width
  SendScintillaMsg pSciWndData,%SCI_SETMARGINTYPEN,2,%SC_MARGIN_SYMBOL              'Margin 0 (Folder margin): Set format
  SendScintillaMsg pSciWndData,%SCI_MARKERSETBACK,25,RGB(255,0,0)                   'Set marker 25 color used for closed subs
  'SendScintillaMsg pSciWndData,%SCI_SETMARGINMASKN,2,%SC_MASK_FOLDERS              'Example only
  'SendScintillaMsg pSciWndData,%SCI_SETMARGINMASKN,2,&B00000110000000000000000000000000  'Show marker at opened and closed subs
  SendScintillaMsg pSciWndData,%SCI_SETMARGINMASKN,2,&B00000010000000000000000000000000  'Show marker at closed subs only (Marker 25)
  '
  'Select the PB lexer, load the PB keyword list and set the different synax colors:
  SendScintillaMsg pSciWndData,%SCI_SETLEXER,%SCLEX_POWERBASIC,0                    'Set PowerBasic lexer
  szBuffer="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#$_%@"    'Characters which may occur in PB keywords
  SendScintillaMsg pSciWndData,%SCI_SETWORDCHARS,0,ByRef szBuffer
  LoadKeywordList hWndParent                                                        'Load the keyword list for syntax coloring
  '
  SendScintillaMsg pSciWndData,%SCI_SETMODEVENTMASK,%SC_MOD_INSERTTEXT Or %SC_MOD_DELETETEXT,0 'Get SCN_MODIFIED event (see WM_NOTIFY)
End Sub
'*************************************************************************************************************************************
Sub LoadKeywordList(ByVal hWndParent As Dword)
  Local hBasicKeywordFile As Dword,hApiKeywordFile As Dword,hConstantKeywordFile As Dword
  Local dwRetVal As Dword,dwFileSize As Dword
  Local hResFind As Dword,hRes As Dword,dwAdrRes As Dword,dwSizeRes As Dword
  'Used global variables: pSciWndData,sBasicKeyWords,sApiKeyWords
  '
  dwRetVal=0    'Set function return value to "success" initially
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  'Now read external keyword list files or create+use new list files with the default content.
  'The default keyword lists are stored as user-defined resources and are loaded if no external keyword files exist.
  'Watch: The length of user-defined resources are DWORD-padded and the padding bytes normally can contain random data.
  'To prevent problems You *must* set trailing padding bytes to NULL because this is handeled correctly by the following routines.
  '
  hBasicKeywordFile=lopen(szBasicKeywordFile,%OF_READ)                        'Does the Basic keyword list file exist?
  If hBasicKeywordFile=%INVALID_HANDLE_VALUE Then                             'No external list file exists
    hBasicKeywordFile=lcreat(szBasicKeywordFile,0)                            'Create new file, stay silent if not able to craeate
    If hBasicKeywordFile<>%INVALID_HANDLE_VALUE Then 
      'Load the default Basic (PB or FB) keyword list from resource (used for syntax coloring and context help):
      Select Case dwCompilerType
      Case %CMPTYPE_FREEBASIC
        hResFind=FindResource(hInst,ByVal %IDRES_FREEBASICKEYWORDS,ByVal %IDREST_KEYWORDS)
      Case Else '%CMPTYPE_POWERBASIC             '%CMPTYPE_FREEBASIC=0, %CMPTYPE_UNKNOWN has the first unused ID
        hResFind=FindResource(hInst,ByVal %IDRES_POWERBASICKEYWORDS,ByVal %IDREST_KEYWORDS)
      End Select
      hRes=LoadResource(hInst,hResFind)                      'Resource handle of the user-defined resource containing the keyword file
      dwAdrRes=LockResource(hRes)                            'Start address of the keyword file in memory
      dwSizeRes=SizeofResource(hInst,hResFind)               'Size of the keyword file in memory (watch: DWORD padded with $Nul!)
      sBasicKeyWords=RTrim$(Peek$(dwAdrRes,dwSizeRes),$NUL)  'Get keywords into string and remove $Nul DWORD padding if existing
      lwrite hBasicKeywordFile,ByVal StrPtr(sBasicKeyWords),Len(sBasicKeyWords)    'Write default list to file
    End If
  Else                                                                    'External list file exists
    dwFileSize=GetFileSize(hBasicKeywordFile,ByVal %NULL)
    If (dwFileSize<>&HFFFFFFFF) And (dwFileSize>0) Then
      sBasicKeyWords=String$(dwFileSize,0)
      lread hBasicKeywordFile,ByVal StrPtr(sBasicKeyWords),Len(sBasicKeyWords)     'Read external list file
    End If
    lclose hBasicKeywordFile
  End If
  '
  hApiKeywordFile=lopen(szApiKeywordFile,%OF_READ)                        'Does the API keyword list file exist?
  If hApiKeywordFile=%INVALID_HANDLE_VALUE Then                           'No external list file exists
    hApiKeywordFile=lcreat(szApiKeywordFile,0)                            'Create new file, stay silent if not able to craeate
    If hApiKeywordFile<>%INVALID_HANDLE_VALUE Then 
      'Load the default API keyword list from resource (used for syntax coloring and context help):
      hResFind=FindResource(hInst,ByVal %IDRES_APIKEYWORDS,ByVal %IDREST_KEYWORDS)
      hRes=LoadResource(hInst,hResFind)                       'Resource handle of the user-defined resource containing the keyword file
      dwAdrRes=LockResource(hRes)                             'Start address of the keyword file in memory
      dwSizeRes=SizeofResource(hInst,hResFind)                'Size of the keyword file in memory (watch: DWORD padded with $Nul!)
      sApiKeyWords=RTrim$(Peek$(dwAdrRes,dwSizeRes),$NUL)     'Get keywords into string and remove $Nul DWORD padding if existing
      lwrite hApiKeywordFile,ByVal StrPtr(sApiKeyWords),Len(sApiKeyWords) 'Write default list to file
    End If
  Else                                                                    'External list file exists
    dwFileSize=GetFileSize(hApiKeywordFile,ByVal %NULL)
    If (dwFileSize<>&HFFFFFFFF) And (dwFileSize>0) Then
      sApiKeyWords=String$(dwFileSize,0)
      lread hApiKeywordFile,ByVal StrPtr(sApiKeyWords),Len(sApiKeyWords)  'Read external list file
    End If
    lclose hApiKeywordFile
  End If
  '
  hConstantKeywordFile=lopen(szConstantKeywordFile,%OF_READ)              'Does the Constant keyword list file exist?
  If hConstantKeywordFile=%INVALID_HANDLE_VALUE Then                      'No external list file exists
    hConstantKeywordFile=lcreat(szConstantKeywordFile,0)                  'Create new file, stay silent if not able to craeate
    If hConstantKeywordFile<>%INVALID_HANDLE_VALUE Then 
      'Load the default constant keyword list from resource (used for syntax coloring and context help):
      hResFind=FindResource(hInst,ByVal %IDRES_CONSTANTKEYWORDS,ByVal %IDREST_KEYWORDS)
      hRes=LoadResource(hInst,hResFind)                        'Resource handle of the user-defined resource containing the keyword file
      dwAdrRes=LockResource(hRes)                              'Start address of the keyword file in memory
      dwSizeRes=SizeofResource(hInst,hResFind)                 'Size of the keyword file in memory (watch: DWORD padded with $Nul!)
      sConstantKeyWords=RTrim$(Peek$(dwAdrRes,dwSizeRes),$NUL) 'Get keywords into string and remove $Nul DWORD padding if existing
      lwrite hConstantKeywordFile,ByVal StrPtr(sConstantKeyWords),Len(sConstantKeyWords) 'Write default list to file
    End If
  Else                                                                    'External list file exists
    dwFileSize=GetFileSize(hConstantKeywordFile,ByVal %NULL)
    If (dwFileSize<>&HFFFFFFFF) And (dwFileSize>0) Then
      sConstantKeyWords=String$(dwFileSize,0)
      lread hConstantKeywordFile,ByVal StrPtr(sConstantKeyWords),Len(sConstantKeyWords)  'Read external list file
    End If
    lclose hConstantKeywordFile
  End If
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  sBasicKeyWordsLCase=" "+LCase$(sBasicKeyWords)+" "                     'Lowercase keyword list for faster search
  sApiKeyWordsLCase=" "+LCase$(sApiKeyWords)+" "                         'Lowercase keyword list for faster search
  sConstantKeyWordsLCase=" "+LCase$(sConstantKeyWords)+" "               'Lowercase keyword list for faster search
  SendScintillaMsg pSciWndData,%SCI_SETKEYWORDS,0,ByVal StrPtr(sApiKeyWordsLCase)      'API keywords must be loaded into list 0
  SendScintillaMsg pSciWndData,%SCI_SETKEYWORDS,1,ByVal StrPtr(sBasicKeyWordsLCase)    'Basic keywords must be loaded into list 1
  SendScintillaMsg pSciWndData,%SCI_SETKEYWORDS,2,ByVal StrPtr(sConstantKeyWordsLCase) 'Constant keywords must be loaded into list 2
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  'DoneLoadKeywordList:
End Sub
'*************************************************************************************************************************************
Sub AutoIndent()
  Static szLineBuffer As Asciiz*1024,lLenLineBuffer As Long,lCurLine As Long,lLineLength As Long,lPrevLineLength As Long
  Static pWord As Word Ptr,i As Long,CurChar As Long
  lLenLineBuffer=SizeOf(szLineBuffer)
  lCurLine=GetCurrentLine()
  lLineLength=SendScintillaMsg(pSciWndData,%SCI_LINELENGTH,lCurLine,0)
  If (lCurLine>0) And (lLineLength<=2) Then  'New empty line and not the very first line
    lPrevLineLength=SendScintillaMsg(pSciWndData,%SCI_LINELENGTH,lCurLine-1,0)
    If lPrevLineLength<SizeOf(szLineBuffer) Then
       SendMessage hWndScintilla,%SCI_GETLINE,lCurLine-1,VarPtr(szLineBuffer)
       Poke VarPtr(szLineBuffer)+lPrevLineLength,0 'Perform NULL rtermination, this is not done by SCI_GETLINE
       For i=0 To lPrevLineLength-1
         CurChar=Peek(VarPtr(szLineBuffer)+i)
         If (CurChar<>&H20) And CurChar<>&H09 Then
           Poke VarPtr(szLineBuffer)+i,0   '&H20=" ",&H09=TAB
           Exit For
         End If
       Next i
       SendScintillaMsg pSciWndData,%SCI_REPLACESEL,0,VarPtr(szLineBuffer)
     End If
   End If
End Sub
'*************************************************************************************************************************************
Function LoadFile(ByVal dwOpenMode As Dword) As Dword   'New file
  'dwOpenMode=%IDC_NEWFILE_EMPTY         New empty file
  'dwOpenMode=%IDC_NEWFILE_BY_TEMPLATE   New file by template
  'dwOpenMode=%IDC_OPEN_FILE             Open existing file
  'Returns values:
  '0: sucessfull
  '1: User has canceled to save changes current listing
  '2: User has canceled while file selection
  '3: Can't find/open file
  '4: Error while reading file
  'Used global variables: hWndMain,hWndScintilla,pSciWndData,szCurFile,szCurDir,szTemplatePath,szFileFltTxt,sFileInformationString
  '
  'If the existing listing has been changed the function asks with cancel opportunity.
  'Then depending on function parameter dwOpenMode the function shows a file selection window.
  'If successfull the function sets the file into the Scintilla windw and resets the "Text changed" flag
  'After the function updates the global variable szCurFile to the current name (probably "").
  'Also the main menu entries "Compile" and "Run" are enabled or disabled".
  'The new listing is searched for an information string at the very end of the listing which contains information about
  'the last caret position and the toggle state of the subs/functions. If found the information string is extracted and
  'removed from the listing before set into the Scintilla window.
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwRetVal As Dword,Ofn As OPENFILENAME,szFileNameTemp As Asciiz*%MAX_PATH,szDirNameTemp As Asciiz*%MAX_PATH
  Static i As Long,j As Long
  Static hFile As Dword,dwFileSize As Dword,pBuffer As Byte Ptr
  Static dwCurPos As Dword,dwCurLine As Dword,dwInfoStringSize As Dword
  '
  dwRetVal=0    'Set function return value initially to "successsfull"
  If SendScintillaMsg(pSciWndData,%SCI_GETMODIFY,0,0)<>0 Then
    Select Case MessageBox(hWndMain,$TEXT_IS_CHANGED+Chr$(13)+$TEXT_CHANGE_IT,$APP_NAME_SHORT,%MB_ICONSTOP Or %MB_YESNOCANCEL Or %MB_DEFBUTTON1)
    Case %IDYES
      If szCurFile="" Then 'No filename
        SaveFileAs
      Else
        SaveFile
      End If
    Case %IDCANCEL
      dwRetVal=1   'Function return value: User has canceled
      GoTo DoneLoadFile
    End Select
  End If
  '
  Select Case dwOpenMode
  Case %IDC_NEWFILE_EMPTY        'New empty file
    'Reset the current editor content:
    SendScintillaMsg pSciWndData,%SCI_CLEARDOCUMENTSTYLE,0,0  'Very important! Otherwise the text loads very slowly
    SendScintillaMsg pSciWndData,%SCI_CLEARALL,0,0
    SendScintillaMsg pSciWndData,%SCI_EMPTYUNDOBUFFER,0,0
    szCurFile=""                         'No file name, szCurDir stays as it is
    SetWindowText hWndMain,$APP_NAME     'Set application name to the caption if no filename is given
    GoTo DoneLoadFile
  Case %IDC_NEWFILE_BY_TEMPLATE          'New file by template
    szDirNameTemp=szTemplateDir
    szFileNameTemp=""
  Case %IDC_OPEN_FILE,%IDC_OPEN_VIRTUAL   'Open existing file
    szDirNameTemp=szCurDir
    szFileNameTemp=szCurFile
  End Select
  '
  If dwOpenMode<>%IDC_OPEN_VIRTUAL Then  'Virtual: Load file without file selection box
    Poke$ VarPtr(Ofn), String$(Len(Ofn),0) 'Fill OPENFILENAME structure initial with 0
    Ofn.lStructSize     = Len(Ofn)
    Ofn.hwndOwner       = hWndMain
    Ofn.hInstance       = hInst
    Ofn.lpstrFilter     = StrPtr(sLoadFltTxt)  'Order: *.bas, *.inc, *.*
    If UCase$(Mid$(szFileNameTemp,Len(szFileNameTemp)-2,3))="INC" Then
      Ofn.nFilterIndex = 2
    Else
      Ofn.nFilterIndex = 1
    End If
    Ofn.lpstrFile       = VarPtr(szFileNameTemp)
    Ofn.lpstrInitialDir = VarPtr(szDirNameTemp)
    Ofn.nMaxFile        = %MAX_PATH
    Ofn.lpfnHook        = CodePtr(OFNHookProc)
    Ofn.lpTemplateName  = %IDD_FILESELDLG
    Ofn.Flags           = %OFN_FILEMUSTEXIST Or %OFN_PATHMUSTEXIST Or %OFN_HIDEREADONLY Or %OFN_EXPLORER Or %OFN_ENABLESIZING Or %OFN_ENABLETEMPLATE Or %OFN_ENABLEHOOK
    'Ofn.FlagsEx        = %OFN_EX_NOPLACESBAR   'Win2000: Don't show icons for favorits, desktop and so on
    If GetOpenFileName(OFN)=0 Then
      dwRetVal=2   '2: User has canceled
      GoTo DoneLoadFile
    End If
  End If
  '
  hFile=lopen(szFileNameTemp,%OF_READ)  
  If hFile=%INVALID_HANDLE_VALUE Then
    MessageBox hWndMain,"Can't find/open file"+Chr$(13)+szFileNameTemp,"",%MB_ICONSTOP
    dwRetVal=3  '3: Can't find/open file
    GoTo DoneLoadFile
  End If
  dwFileSize=GetFileSize(hFile,ByVal %NULL)
  pBuffer=GlobalAlloc(%GMEM_FIXED,dwFileSize+4)         'Plus (at least) one byte for NULL termination
  If lread(hFile,ByVal pBuffer,dwFileSize)=dwFileSize Then
    If dwOpenMode=%IDC_NEWFILE_BY_TEMPLATE Then         '%IDC_NEWFILE_BY_TEMPLATE: New file by template
      szCurFile=""                                      'No file name, szCurDir stays as it is
    Else                                                '%IDC_OPEN_FILE: Open existing file
      szCurFile=szFileNameTemp
      szCurDir=Left$(szCurFile,InStr(-1,szCurFile,"\")) 'With ending "\"
    End If
    If szCurFile="" Then
      SetWindowText hWndMain,$APP_NAME                  'Set application name to the caption if no filename is given
    Else
      SetWindowText hWndMain,szCurFile                  'Set file name to the caption
    End If
    '
    'The listing can (must not) contain a PBE/BE information string (caret position/sub toggle states) at the very end of
    'the listing. Extract the information string into the global variable sFileInformationString if found:
    sFileInformationString=""
    i=pBuffer+dwFileSize-1
    j=0   'Line counter
    Do
      Decr i
      If Peek(i)=13 Then
        If (Peek$(i,Len($PBESETTINGS))=$PBESETTINGS) Or _        'There is a (old format) PBE information string in the listing
            Peek$(i,Len($BESETTINGS))=$BESETTINGS Then           'There is a (new format) BE information string in the listing
          sFileInformationString=Peek$(i,pBuffer+dwFileSize-i)   'Store information into global string to process it after timer expires
          dwFileSize=i-pBuffer                                   'File size without the information string
          Exit Do
        Else 
          Incr j                                                 'Increment line counter
          If j>20 Then                                           'No file information string found
            sFileInformationString=""
            Exit Do
          End If
        End If
      End If
    Loop Until i=pBuffer
    Poke pBuffer+dwFileSize+1,%NULL                          'Perform NULL termination of the text (needed only if SCI_SETTEXT used)   
    '
    SendScintillaMsg pSciWndData,%SCI_CLEARDOCUMENTSTYLE,0,0  'Very important! Otherwise the text loads very slowly
    SendScintillaMsg pSciWndData,%SCI_CLEARALL,0,0
    SendScintillaMsg pSciWndData,%SCI_ADDTEXT,ByVal dwFileSize,ByVal pBuffer
    SendScintillaMsg pSciWndData,%SCI_EMPTYUNDOBUFFER,0,0
    If Len(sFileInformationString) Then
      'First go to the very last line. This results processing the lexers folding information so that we are able
      'to toggle the subs/functions. Then we give Scintilla a bit time to do the job by starting a timer.
      'When the timer expires (WM_TIMER message) we can toggle the functions as stored in the information string.
      SendScintillaMsg pSciWndData,%SCI_GOTOLINE,SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0),0
      SetTimer hWndMain,1,55,ByVal 0 'Handle information string after WM_TIMER
    Else
      SendScintillaMsg pSciWndData,%SCI_GOTOPOS,0,0    'Set Caret to begin of text
    End If
  Else 'Read error
    MessageBox hWndMain,"Error while reading from file"+Chr$(13)+szFileNameTemp,"",%MB_ICONSTOP
    dwRetVal=4  '4: Error while reding file
  End If
  lclose hFile
  GlobalFree pBuffer
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneLoadFile:
  SetFocus hWndScintilla
  '
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Sub ProcessListingSettings()
  'This function is called after loading a new file from disk if there is a file information string found in the listing.
  'If so, LoadFile() stores this information into the global string sFileInformationString. The information string
  'starts with $BESETTINGS (this is Chr$(13,10)+"'BESETTINGS=").
  '
  'We start first with $BESETTINGS (Chr$(13,10)+"'BESETTINGS (don't change!):"). After there follows:
  '$BECURSOR: (Chr$(13,10)+"'BECURSOR=") followed by the Hex number coding current cursor position
  '$BETOGGLE: (Chr$(13,10)+"'BETOGGLE=") followed by a list of "1"/"0" presenting the toggle state of the subs/functions/macros.
  '$BETARGET: (Chr$(13,10)+"'BETARGET=") followed by the Hex number coding the project's target file type (%TARGET_... constant)
  '$BERESFILE: (Chr$(13,10)+"'BERESFILE=") followed by the resource filename (*.res) as plain text
  '$BEOUTFILE: (Chr$(13,10)+"'BEOUTFILE=") followed by the (alternative) output filename as plain text
  '
  'The caret position we could restore immediately after setting the new listing into Scintilla. But to restore the
  'toggle states of the subs we first must wait until Scintilla has processed the new file completely. Otherwise no
  'toggling whould be done. Therefore LoadFile() doesn't call this function directly. Instead LoadFile() starts a timer.
  'After the resulting WM_TIMER message this function is called.
  '
  'Used global variables: sFileInformationString,pSciWndData
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwCurCaretPos As Dword,dwCurLine As Dword,dwCurToggleFlag As Dword,sToggleFlags As String
  Static lStartOfExpr As Long,lEndOfExpr As Long,sCurExprValue As String
  If Len(sFileInformationString)=0 Then GoTo DoneProcessListingSettings  'Error preventer
  '
  If Left$(sFileInformationString,Len($PBESETTINGS))=$PBESETTINGS Then         'Old PBESETTINGS format used
    dwCurCaretPos=Val("&H"+Mid$(sFileInformationString,Len($PBESETTINGS)+1,8)) 'Get current caret position
    sToggleFlags=Mid$(sFileInformationString,Len($PBESETTINGS)+9)              'Get toogle flag list by deleting caret position information
  Else                                                                         'New BESETTINGS format used
    'Get current caret position:
    lStartOfExpr=InStr(sFileInformationString,$BECURSOR)
    If lStartOfExpr=0 Then                                                     'Key not found: Set default value
      dwCurCaretPos=Val("&H"+sCurExprValue)                                    'Set current caret position to 0 (start of listing)
    Else                                                                       'Key found: Retrieve value
      lStartOfExpr=lStartOfExpr+Len($BECURSOR)                                 'Set start to begin of value
      lEndOfExpr=InStr(lStartOfExpr,sFileInformationString,Any $CRLF)          'Next Cr+Rt terminates current expression
      If lEndOfExpr=0 Then                                                     'No Cr+Rt found: Use end of string as end of expression
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr)
      Else
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr,lEndOfExpr-lStartOfExpr)
      End If
      dwCurCaretPos=Val("&H"+sCurExprValue)                                    'Get current caret position
    End If
    '
    'Get current sub/function/macro toggle states:
    lStartOfExpr=InStr(sFileInformationString,$BETOGGLE)
    If lStartOfExpr=0 Then                                                     'Key not found: Set default value
      sToggleFlags=""                                                          'No toggle flags available
    Else                                                                       'Key found: Retrieve value
      lStartOfExpr=lStartOfExpr+Len($BETOGGLE)                                 'Set start to begin of value
      lEndOfExpr=InStr(lStartOfExpr,sFileInformationString,Any $CRLF)          'Next Cr+Rt terminates current expression
      If lEndOfExpr=0 Then                                                     'No Cr+Rt found: Use end of string as end of expression
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr)
      Else
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr,lEndOfExpr-lStartOfExpr)
      End If
      sToggleFlags=sCurExprValue                                               'Get current Toggle flags
    End If
    '
    'Project settings: Get project's target file type:
    lStartOfExpr=InStr(sFileInformationString,$BETARGET)
    If lStartOfExpr=0 Then                                                     'Key not found: Set default value
      ProjectSettings.dwTargetFileType=0                                       'Default target file type
    Else                                                                       'Key found: Retrieve value
      lStartOfExpr=lStartOfExpr+Len($BETARGET)                                 'Set start to begin of value
      lEndOfExpr=InStr(lStartOfExpr,sFileInformationString,Any $CRLF)          'Next Cr+Rt terminates current expression
      If lEndOfExpr=0 Then                                                     'No Cr+Rt found: Use end of string as end of expression
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr)
      Else
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr,lEndOfExpr-lStartOfExpr)
      End If
      ProjectSettings.dwTargetFileType=Val("&H"+sCurExprValue)                 'Get the project's target file type
    End If
    '
    'Project settings: Get project's resource file:
    lStartOfExpr=InStr(sFileInformationString,$BERESFILE)
    If lStartOfExpr=0 Then                                                     'Key not found: Set default value
      ProjectSettings.szResFile=""                                             'No resource file specified
    Else                                                                       'Key found: Retrieve value
      lStartOfExpr=lStartOfExpr+Len($BERESFILE)                                'Set start to begin of value
      lEndOfExpr=InStr(lStartOfExpr,sFileInformationString,Any $CRLF)          'Next Cr+Rt terminates current expression
      If lEndOfExpr=0 Then                                                     'No Cr+Rt found: Use end of string as end of expression
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr)
      Else
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr,lEndOfExpr-lStartOfExpr)
      End If
      ProjectSettings.szResFile=sCurExprValue                                  'Get the project's resource file name
    End If
    '
    'Project settings: Get project's output filename:
    lStartOfExpr=InStr(sFileInformationString,$BEOUTFILE)
    If lStartOfExpr=0 Then                                                     'Key not found: Set default value
      ProjectSettings.szTargetFilename=""                                      'No user-defined output filename specified
    Else                                                                       'Key found: Retrieve value
      lStartOfExpr=lStartOfExpr+Len($BEOUTFILE)                                'Set start to begin of value
      lEndOfExpr=InStr(lStartOfExpr,sFileInformationString,Any $CRLF)          'Next Cr+Rt terminates current expression
      If lEndOfExpr=0 Then                                                     'No Cr+Rt found: Use end of string as end of expression
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr)
      Else
        sCurExprValue=Mid$(sFileInformationString,lStartOfExpr,lEndOfExpr-lStartOfExpr)
      End If
      ProjectSettings.szTargetFilename=sCurExprValue                           'Get the project's user-defined output filename
    End If
  End If   'New/old PBESETTINGS format used
  '
  'Perform sub/function/macro toggling:
  If Len(sToggleFlags)<>0 Then                                                 'If toggle information available
    dwCurToggleFlag=0
    SendScintillaMsg pSciWndData,%SCI_SETFOLDLEVEL,0,%SC_FOLDLEVELHEADERFLAG  'Line 0 acts as a head line as it whould be a Sub
    For dwCurLine=0 To SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0)    'Find the first sub
      If (SendScintillaMsg(pSciWndData,%SCI_GETFOLDLEVEL,dwCurLine,0) And %SC_FOLDLEVELHEADERFLAG) Then 'Head line found
        Incr dwCurToggleFlag
        If Mid$(sToggleFlags,dwCurToggleFlag,1)="1" Then 'Current flag is "1": Open the current sub/function
          If SendScintillaMsg(pSciWndData,%SCI_GETFOLDEXPANDED,dwCurLine,0)=0 Then '0: Sub is currently open
            SendScintillaMsg pSciWndData,%SCI_TOGGLEFOLD,dwCurLine,0
          End If
        Else                                           'Current flag is "0" (other then "1"): Close the current sub/function
          If SendScintillaMsg(pSciWndData,%SCI_GETFOLDEXPANDED,dwCurLine,0) Then 'True: Sub is currently closed
            SendScintillaMsg pSciWndData,%SCI_TOGGLEFOLD,dwCurLine,0
          End If
        End If
        If dwCurToggleFlag>=Len(sToggleFlags) Then Exit For  'All flags processed
      End If
    Next dwCurLine
  End If
  '
  'Set caret position and go to this position:
  dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwCurCaretPos,0)
  SendScintillaMsg pSciWndData,%SCI_LINESCROLL,0,dwCurLine     'Scroll display by the number of columns+lines (first visible line)
  SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwCurLine,0  'Open the sub containing this line if necessary for the current position
  SendScintillaMsg pSciWndData,%SCI_GOTOPOS,dwCurCaretPos,0    'Finally set Caret to the stored position
  '
  sFileInformationString=""
  sToggleFlags=""
  sCurExprValue=""
  DoneProcessListingSettings:
End Sub
'*************************************************************************************************************************************
Function SaveFileAs() As Dword
  'Opens a "Save As" dialog. If the user doesn't cancel this fuinction calls the function SaveFile().
  'The function updates the global variables szCurFile and szCurDir if sucessfull and updates the main window's caption bar.
  'Return values: 0 if sucsessfull, 1 if the user has canceled. Above the error values of SaveFile() are returned.
  'Used global variables: pSciWndData,hWndMain,szCurFile,szCurDir
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwRetVal As Dword,Ofn As OPENFILENAME,szFileNameTemp As Asciiz*%MAX_PATH,szDirNameTemp As Asciiz*%MAX_PATH
  Static szFileExtension As Asciiz*5,i As Long
  '
  If szCurFile="" Then           'No filename for the current file given
    If szCurDir="" Then          'Also no last Directory
      szDirNameTemp=szEditorDir  'Most people hate the Explorer default - so set the editor directory as default
    Else
      szDirNameTemp=szCurDir
    End If
    szFileNameTemp=""
  Else
    szFileNameTemp=szCurFile
    szDirNameTemp=szCurDir
  End If
  '
  Poke$ VarPtr(Ofn), String$(Len(Ofn),0) 'Fill OPENFILENAME structure initial with 0
  Ofn.lStructSize     = Len(Ofn)
  Ofn.hwndOwner       = hWndmain
  Ofn.hInstance       = hInst
  Ofn.lpstrFilter     = StrPtr(sSaveFltTxt)  'Order: *.bas, *.inc, *.rtf, *.*
  If UCase$(Mid$(szFileNameTemp,Len(szFileNameTemp)-2,3))="INC" Then
    Ofn.nFilterIndex = 2
  Else
    Ofn.nFilterIndex = 1
  End If
  Ofn.lpstrInitialDir = VarPtr(szDirNameTemp)
  Ofn.lpstrFile       = VarPtr(szFileNameTemp)
  Ofn.nMaxFile        = %MAX_PATH
  Ofn.lpfnHook        = CodePtr(OFNHookProc)
  Ofn.lpTemplateName  = %IDD_FILESELDLG
  Ofn.Flags           = %OFN_OVERWRITEPROMPT Or %OFN_PATHMUSTEXIST Or %OFN_HIDEREADONLY  Or %OFN_EXPLORER Or %OFN_ENABLESIZING Or %OFN_ENABLETEMPLATE Or %OFN_ENABLEHOOK
  'Ofn.FlagsEx        = %OFN_EX_NOPLACESBAR   'Win2000: Don't show icons for favorits, desktop and so on
  If GetSaveFileName(OFN)=0 Then
    Function=2   '2: User has canceled
  Else
    szFileExtension=UCase$(Right$(szFileNameTemp,4))
    If szFileExtension<>".BAS" And szFileExtension<>".INC" And szFileExtension<>".RTF" Then 'No valid extension
      i=InStr(-1,szFileNameTemp,".")
      If i=Len(szFileNameTemp) Then szFileNameTemp=Left$(szFileNameTemp,i-1)  'Remove "." if at the very end
      Select Case Ofn.nFilterIndex    'Order: *.bas, *.inc, *.rtf, *.* - append extension depending on current filter setting
      Case 2
        szFileNameTemp=szFileNameTemp+".inc"
      Case 3
        szFileNameTemp=szFileNameTemp+".rtf"
      Case Else '1 (bas) or 4 (*.*)
        szFileNameTemp=szFileNameTemp+".bas"
      End Select
      szFileExtension=UCase$(Right$(szFileNameTemp,4))
    End If
    If szFileExtension=".RTF" Then
      Function=SaveRtfFile(szFileNameTemp)
    Else
      szCurFile=szFileNameTemp                          'Update current filename
      szCurDir=Left$(szCurFile,InStr(-1,szCurFile,"\")) 'With ending "\"
      SetWindowText hWndMain,szCurFile                  'Set file name to the caption
      Function=SaveFile()
    End If
  End If
End Function
'*************************************************************************************************************************************
Function SaveFile() As Dword
  'Saves the currently loaded file to disk. Shows MessageBox if error. No action but error MessageBox if szCurFile="".
  'Also the main menu entries "Compile" and "Run" are enabled or disabled".
  'Return values:
  '0 if sucsessfull
  '1 if no file is opened (szCurFile="")
  '2 Couldn't create/open the file
  '3 Write error
  'Used global variables: pSciWndData,hWndMain,szCurFile
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwRetVal As Dword,dwFileSize As Dword,pBuffer As Byte Ptr,hFile As Dword
  Static dwCurPos As Dword,sEditorSettings As String,sTemp As String,dwCurLine As Dword
  '
  dwRetVal=0    'Set function return value initially to "successsfull"
  hFile=%INVALID_HANDLE_VALUE
  pBuffer=0
  '
  If szCurFile="" Then
    dwRetVal=1   'No file opened
    GoTo DoneSaveFile
  End If
  '
  dwFileSize=SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)
  pBuffer=GlobalAlloc(%GMEM_FIXED,dwFileSize+1)                                           'Plus one terminating NULL character
  dwFileSize=SendScintillaMsg(pSciWndData,%SCI_GETTEXT,ByVal dwFileSize+1,ByVal pBuffer)  'Plus one terminating NULL character
  hFile=lcreat(szCurFile,0)  
  If hFile=%INVALID_HANDLE_VALUE Then
    dwRetVal=2 'Couldn't create/open the file
    GoTo DoneSaveFile
  End If
  '
  If lwrite(hFile,ByVal pBuffer,dwFileSize)<>dwFileSize Then
    dwRetVal=3 'Write error
    GoTo DoneSaveFile
  End If
  '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  'Now store the current editor settings (current line and toggled/untoggled subs) and the project settings at the end of the file.
  'The setting text is not visible for the user because we remove it, before setting the file when reading in.
  '
  'We start first with $BESETTINGS (Chr$(13,10)+"'BESETTINGS (don't change!):"). After there follows:
  '$BECURSOR: (Chr$(13,10)+"'BECURSOR=") followed by the Hex number coding current cursor position
  '$BETOGGLE: (Chr$(13,10)+"'BETOGGLE=") followed by a list of "1"/"0" presenting the toggle state of the subs/functions/macros.
  '$BETARGET: (Chr$(13,10)+"'BETARGET=") followed by the Hex number coding the project's target file type (%TARGET_... constant)
  '$BERESFILE: (Chr$(13,10)+"'BERESFILE=") followed by the resource filename (*.res) as plain text
  '$BEOUTFILE: (Chr$(13,10)+"'BEOUTFILE=") followed by the (alternative) output filename as plain text
  '
  'First set the start of BESETTINGS:
  sEditorSettings=$BESETTINGS
  '
  'Get the current cursor position and store:
  dwCurPos=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)    'Get the current cursor position
  sEditorSettings=sEditorSettings+$BECURSOR+Hex$(dwCurPos)
  '
  'Get the current toggle states and store:
  sTemp=$BETOGGLE
  For dwCurLine=0 To SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0)                     'Find the first sub
    If (SendMessage(hWndScintilla,%SCI_GETFOLDLEVEL,dwCurLine,0) And %SC_FOLDLEVELHEADERFLAG) Then 'Head line found
      If SendScintillaMsg(pSciWndData,%SCI_GETFOLDEXPANDED,dwCurLine,0)=0 Then '0: Sub is currently closed
        sTemp=sTemp+"0"
      Else
        sTemp=sTemp+"1"
      End If
    End If
  Next dwCurLine
  sEditorSettings=sEditorSettings+sTemp
  '
  If dwCompilerType<>%CMPTYPE_POWERBASIC Then  'For PowerBasic we don't store project settings
    'Target file type (console exe, gui exe, dll and so on), %TARGET_... ID:
    sEditorSettings=sEditorSettings+$BETARGET+Hex$(ProjectSettings.dwTargetFileType)
    '
    'Resource file (*.res) if specified:
    If Len(ProjectSettings.szResFile) Then sEditorSettings=sEditorSettings+$BERESFILE+ProjectSettings.szResFile
    '
    'Target filename if specified:
    If Len(ProjectSettings.szTargetFilename) Then sEditorSettings=sEditorSettings+$BEOUTFILE+ProjectSettings.szTargetFilename
  End If  'If dwCompilerType<>%CMPTYPE_POWERBASIC
  '
  'Now append to file:
  If lwrite(hFile,ByVal StrPtr(sEditorSettings),Len(sEditorSettings))<>Len(sEditorSettings) Then 'Append the Setting string
    dwRetVal=3 'Write error
    GoTo DoneSaveFile
  End If
  '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  SendScintillaMsg pSciWndData,%SCI_SETSAVEPOINT,0,0  'Reset Scintilla's "Modified" flag
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneSaveFile:
  If pBuffer<>0 Then GlobalFree pBuffer
  If hFile<>%INVALID_HANDLE_VALUE Then lclose hFile
  sEditorSettings=""
  sTemp=""
  '
  Select Case dwRetVal
  Case 1
    MessageBox hWndMain,"No file opened.","",%MB_ICONSTOP
  Case 2
    MessageBox hWndMain,"Couldn't create/overwrite the file"+Chr$(13)+szCurFile,"",%MB_ICONSTOP
  Case 3
    MessageBox hWndMain,"Error when writing to file"+Chr$(13)+szCurFile,"",%MB_ICONSTOP
  End Select
  '
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Function SaveRtfFile(szFilename As Asciiz) As Dword
  'Saves the currently loaded file in RTF text format to disk. Shows MessageBox if error.
  'Return values:
  '0 if sucsessfull
  '1 No filename
  '2 Couldn't create/open the file
  '3 Write error
  'Used global variables: pSciWndData,hWndMain,szCurFile
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwRetVal As Dword,dwFileSize As Dword,hFile As Dword,TxtRange As TEXTRANGE
  Static pCurChar As Byte Ptr,pCurStyle As Byte Ptr,bLastStyle As Byte,sBuffer As String,i As Long
  Static bRed As Byte,bGreen As Byte,bBlue As Byte
  '  
  dwRetVal=0    'Set function return value initially to "successsfull"
  hFile=%INVALID_HANDLE_VALUE
  TxtRange.lpstrText=0
  '
  If szFilename="" Then
    dwRetVal=1   'No filename
    GoTo DoneSaveFile
  End If
  '
  SetCursor LoadCursor(%NULL,ByVal %IDC_APPSTARTING)   'For very long listings the RTF export needs a bit time, show hourglass mouse
  '
  dwFileSize=(SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)*2)+2   '1 cell needs 2 bytes plus 2 terminating NULL characters
  TxtRange.chrg.cpMin=0
  TxtRange.chrg.cpMax=SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)
  TxtRange.lpstrText=GlobalAlloc(%GMEM_FIXED,dwFileSize)
  SendScintillaMsg pSciWndData,%SCI_GETSTYLEDTEXT,0,ByRef TxtRange

  hFile=lcreat(szFilename,0)
  If hFile=%INVALID_HANDLE_VALUE Then
    dwRetVal=2 'Couldn't create/open the file
    GoTo DoneSaveFile
  End If
  '
  'First create the RTF header and the one and only used font:
  sBuffer="{\rtf1\ansi\deff0{\fonttbl{\f0\fmodern\fcharset0 "+Extract$(szUserFont,$NUL)+";}}"  '+Chr$(13,10)
  'Now add the color table from the current set sayntax colors. An example of a RTF color table is:
  '"{\colortbl \red0\green0\blue255;\red255\green0\blue0;\red0\green128\blue0;\red0\green255\blue255;}"+Chr$(13,10)+_
  sBuffer=sBuffer+"{\colortbl "
  For i=0 To ArrayAttr(UserColor(),4)-1  'All DIMed elements of the user color table
    bRed=  LoByt(UserColor(i))
    bGreen=HiByt(LoWrd(UserColor(i)))
    bBlue=LoByt(HiWrd(UserColor(i)))
    sBuffer=sBuffer+"\red"+LTrim$(Str$(bRed))+"\green"+LTrim$(Str$(bGreen))+"\blue"+LTrim$(Str$(bBlue))+";"
  Next i
  sBuffer=sBuffer+"}"  '+Chr$(13,10)
  'Now we add the start of the text:
  sBuffer=sBuffer+"\pard\f0\fs"+LTrim$(Str$(dwUserFontSize*2))+" "  '+Chr$(13,10)
  If lwrite(hFile,ByVal StrPtr(sBuffer),Len(sBuffer))<>Len(sBuffer) Then   'Write RTF header and text start
    dwRetVal=3 'Write error
    GoTo DoneSaveFile
  End If

  'Each character is given as a Cell of 2 bytes. The lower byte contains the character and the upper byte the style information.
  'The lowest 5 bits of the Style byte contain the text attributes (values 0...31).
  bLastStyle=0
  sBuffer=""
  For pCurChar=TxtRange.lpstrText To TxtRange.lpstrText+dwFileSize-4 Step 2
    pCurStyle=pCurChar+1
    If bLastStyle<>(@pCurStyle And &B00011111) Then  'Only the lower 5 bits are interesting for us (text attributes)
      bLastStyle=@pCurStyle
      If (@pCurChar<>10 And @pCurChar<>13) Then  'If no line end character
        sBuffer=sBuffer+"\cf"+LTrim$(Str$(bLastStyle))+" "
      End If
    End If
    If (@pCurChar<>10 And @pCurChar<>13) Then  'If no line end character
      Select Case @pCurChar
      Case &H5C,&H7B,&H7D  '&H5C="\", &H7B="{", &H7D="}" - these are special characters in RTF files 
        sBuffer=sBuffer+"\"+Chr$(@pCurChar)
      Case Else
        sBuffer=sBuffer+Chr$(@pCurChar)
      End Select
    End If
    If @pCurChar=10 Then 'End of line: save
      sBuffer=sBuffer+"\par"   '+Chr$(13,10)
      If lwrite(hFile,ByVal StrPtr(sBuffer),Len(sBuffer))<>Len(sBuffer) Then
        dwRetVal=3 'Write error
        Exit For
      End If
      sBuffer=""
    End If
  Next pCurChar
  sBuffer=sBuffer+"\par}"   'Last line and RTF end     sBuffer=sBuffer+"\par"+Chr$(13,10)+"}"  
  If lwrite(hFile,ByVal StrPtr(sBuffer),Len(sBuffer))<>Len(sBuffer) Then
    dwRetVal=3 'Write error
  End If
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneSaveFile:
  SetCursor LoadCursor(%NULL,ByVal %IDC_ARROW)   'Show standard mouse
  '
  If TxtRange.lpstrText<>0 Then GlobalFree TxtRange.lpstrText
  If hFile<>%INVALID_HANDLE_VALUE Then lclose hFile
  sBuffer=""
  '
  Select Case dwRetVal
  Case 1
    MessageBox hWndMain,"Can't save, no filename.","",%MB_ICONSTOP
  Case 2
    MessageBox hWndMain,"Couldn't create/overwrite the file"+Chr$(13)+szCurFile,"",%MB_ICONSTOP
  Case 3
    MessageBox hWndMain,"Error when writing to file"+Chr$(13)+szCurFile,"",%MB_ICONSTOP
  End Select
  Function=dwRetVal
End Function
'**************************************************************************************************************************************
Function OFNHookProc(ByVal hDlg As Dword, ByVal Msg As Dword,ByVal wParam As Dword, ByVal lParam As Dword) As Long
  'Hook function for Explorer style file selection dialogs (GetSaveFileName/GetOpenFileName).
  'The hook funktion is called after user activities in file selection dialog.
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static szBuffer As Asciiz*%MAX_PATH,hFile As Dword,pOfNotify As OFNOTIFY Ptr,RctDlg As RECTL,RctControl As RECTL,hWndControl As Dword
  Static i As Dword,szCurDirInternal As Asciiz*%MAX_PATH,szCurFileBuffer As Asciiz*%MAX_PATH,dwCurFileFilter As Dword
  '
  Select Case Msg
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDC_GOTOCURDIR,%IDC_GOTOINCDIR
      GetDlgItemText GetParent(hDlg),%IDC_OFN_FILENAME,szCurFileBuffer,SizeOf(szCurFileBuffer) 'Store current filename
      If IsDlgButtonChecked(hDlg,%IDC_GOTOCURDIR)=%BST_CHECKED Then
        SetDlgItemText GetParent(hDlg),%IDC_OFN_FILENAME,szCurDirInternal                        'Set target dir as current filename
      Else
        SendMessage GetParent(hDlg),%CDM_GETFOLDERPATH,ByVal SizeOf(szCurDirInternal),ByVal VarPtr(szCurDirInternal)  'Store current path
        Select Case SendDlgItemMessage(GetParent(hDlg),%IDC_OFN_FILETYPE,%CB_GETCURSEL,0,0)  'Store current file filter
        Case 0 'Basic files
          szCurDirInternal=szCurDirInternal+"\*.bas"
        Case 1 'Include files
          szCurDirInternal=szCurDirInternal+"\*.inc"
        End Select
        szBuffer=szIncDir+"*.*"                                                                'Watch: szIncDir has a trailing Backslash!
        SetDlgItemText GetParent(hDlg),%IDC_OFN_FILENAME,szBuffer                              'Set target dir as current filename
      End If
      SendMessage GetParent(hDlg),%WM_COMMAND,%IDC_OFN_OPENSAVE,0                              'No "push" OK (this changes the dir)
      SetDlgItemText GetParent(hDlg),%IDC_OFN_FILENAME,szCurFileBuffer                         'Finally set stored filename back
    End Select
  Case %WM_NOTIFY
    pOfNotify=lParam    'lParam of WM_NOTIFY is a OFNOTIFY structure pointer
    If @pOfNotify.hdr.code=%CDN_SELCHANGE Or @pOfNotify.hdr.code=%CDN_FOLDERCHANGE Then  'New file selected
      SendMessage @pOfNotify.hdr.hwndFrom,%CDM_GETFILEPATH,ByVal SizeOf(szBuffer),ByVal VarPtr(szBuffer)  'Get Path+filename
      If @pOfNotify.hdr.code=%CDN_SELCHANGE Then
        hFile=lopen(szBuffer,%OF_READ)
        If hFile=%INVALID_HANDLE_VALUE Then
          szBuffer=""
        Else
          lread hFile,szBuffer,SizeOf(szBuffer)                    'Read MAX_PATH bytes
          lclose hFile
          szBuffer=Trim$(szBuffer)
          If Left$(szBuffer,1)="'" Then szBuffer=Mid$(szBuffer,2)  'Remove comment stroke if very first character of line
          i=InStr(szBuffer,Chr$(13))
          If i Then szBuffer=Left$(szBuffer,i-1)                   'Show first line only
        End If
      End If
      SetDlgItemText hDlg,%IDC_FIRSTLINIE,szBuffer             'Copy into static text control
    End If
  Case %WM_SIZE,%WM_INITDIALOG
    'Move/resize info control:
    hWndControl=GetDlgItem(hDlg,%IDC_FIRSTLINIE)
    GetWindowRect hDlg,RctDlg
    GetWindowRect hWndControl,RctControl
    RctControl.nLeft=5         'Left position in file selection dialog
    RctControl.nBottom=(RctControl.nBottom-RctControl.nTop)  'Height
    RctControl.nTop=RctControl.nTop-RctDlg.nTop            'Top position in file selection dialog
    RctControl.nRight=(RctDlg.nRight-RctDlg.nLeft)-134                        'Width
    MoveWindow hWndControl,RctControl.nLeft,RctControl.nTop,RctControl.nRight,RctControl.nBottom,%TRUE
    InvalidateRect hWndControl,ByVal %NULL,%FALSE    'Sometimes a part of the text isn't redrawed without this call
    '
    'Move the directory radio buttons:
    hWndControl=GetDlgItem(hDlg,%IDC_GOTOCURDIR)  'RadioButton "Current directory"
    RctControl.nLeft=(RctDlg.nRight-RctDlg.nLeft)-125        'Left position in file selection dialog
    RctControl.nTop=RctControl.nTop+2            'Top position in file selection dialog
    RctControl.nRight=135 'Width
    RctControl.nBottom=12 'Height
    MoveWindow hWndControl,RctControl.nLeft,RctControl.nTop,RctControl.nRight,RctControl.nBottom,%TRUE
    InvalidateRect hWndControl,ByVal %NULL,%FALSE    'Sometimes a part of the text isn't redrawed without this call
    '
    hWndControl=GetDlgItem(hDlg,%IDC_GOTOINCDIR)  'RadioButton "Include directory"
    RctControl.nLeft=(RctDlg.nRight-RctDlg.nLeft)-125        'Left position in file selection dialog
    RctControl.nTop=RctControl.nTop+14            'Top position in file selection dialog
    RctControl.nRight=135 'Width
    RctControl.nBottom=12 'Height
    MoveWindow hWndControl,RctControl.nLeft,RctControl.nTop,RctControl.nRight,RctControl.nBottom,%TRUE
    InvalidateRect hWndControl,ByVal %NULL,%FALSE    'Sometimes a part of the text isn't redrawed without this call
    '
    If Msg=%WM_INITDIALOG Then
      If Len(szIncDir) Then 'Include directory exisat (specified by the user)
        CheckDlgButton hDlg,%IDC_GOTOCURDIR,%BST_CHECKED     'Initial select RadioButton "Current directory"
      Else
        EnableWindow GetDlgItem(hDlg,%IDC_GOTOCURDIR),%FALSE 'Disable RadioButton "(GoTo) Current directory"
        EnableWindow GetDlgItem(hDlg,%IDC_GOTOINCDIR),%FALSE 'Disable RadioButton "(GoTo) Include directory"
      End If
      Function=%TRUE
    Else   '%WM_SIZE
      Function=0
    End If
  End Select
End Function
'***************************************************************************************************************************************
Sub CheckMarginWidth() 'New line
  'Checks the Line number margin width depending on the current number of lines and corrects it if necessary
  'Used global variables: pSciWndData
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwNumLines As Dword,szBuffer As Asciiz*32,dwOldMarginWidth As Dword,dwNewMarginWidth As Dword
  
  dwNumLines=SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0) 'How many lines has the listing now?
  szBuffer=Str$(dwNumLines)
  dwNewMarginWidth=SendScintillaMsg(pSciWndData,%SCI_TEXTWIDTH,%STYLE_LINENUMBER,ByVal VarPtr(szBuffer))+2 'Get the needed margin width
  dwOldMarginWidth=SendScintillaMsg(pSciWndData,%SCI_GETMARGINWIDTHN,1,0)
  If dwOldMarginWidth<dwNewMarginWidth Then                                     'If margin 1 (line numbers) ist too small...
    SendScintillaMsg pSciWndData,%SCI_SETMARGINWIDTHN,1,dwNewMarginWidth        'Set new width of Margin 1
  ElseIf dwOldMarginWidth>dwNewMarginWidth+3 Then                               'If margin 1 (line numbers) ist too big...
    SendScintillaMsg pSciWndData,%SCI_SETMARGINWIDTHN,1,dwNewMarginWidth        'Set new width of Margin 1
  End If
End Sub
'*************************************************************************************************************************************
Sub SetUserFont()
  Static i As Long,szBuffer As Asciiz*50
  'Sets the user-selected font, the syntax colors and the TAB width
  'Used global variables: pSciWndData, szUserFont, dwUserFontSize, Type UserColor
  SendScintillaMsg pSciWndData,%SCI_STYLESETFONT,%STYLE_DEFAULT,ByRef szUserFont          'Set the Font
  SendScintillaMsg pSciWndData,%SCI_STYLESETSIZE,%STYLE_DEFAULT,dwUserFontSize            'Set the Font size in points
  SendScintillaMsg pSciWndData,%SCI_STYLESETBOLD,%STYLE_DEFAULT,0                         'Set the Font to non-bold
  SendScintillaMsg pSciWndData,%SCI_STYLESETITALIC,%STYLE_DEFAULT,0                       'Set the Font to non-italic
  SendScintillaMsg pSciWndData,%SCI_SETCONTROLCHARSYMBOL,&H20,0                     'Space as Control Character instead of ,"NUL","ESC" and so on
  SendScintillaMsg pSciWndData,%SCI_STYLECLEARALL,0,0                               'Set all other styles to the default
  '
  'szBuffer="Arial"
  'SendScintillaMsg pSciWndData,%SCI_STYLESETFONT,%SCE_B_COMMENT,ByRef szBuffer          'Set the comment Font
  '
  szBuffer="Arial"
  SendScintillaMsg pSciWndData,%SCI_STYLESETSIZE,%STYLE_LINENUMBER,dwUserFontSize-1  'Set the Font size for the line numbers
  SendScintillaMsg pSciWndData,%SCI_STYLESETFONT,%STYLE_LINENUMBER,ByRef szBuffer    'Set the Font for the line numbers
  '
  'Set colors for selected text:
  SendScintillaMsg pSciWndData,%SCI_SETSELFORE,1,RGB(255,255,255)                         'RGB(255,255,255)=white
  SendScintillaMsg pSciWndData,%SCI_SETSELBACK,1,RGB(0,0,0)                               'RGB(0,0,0)=black

  'Set colors for syntax coloring:
  For i=%SCE_B_DEFAULT To ArrayAttr(UserColor(),4)-1 '%SCE_B_DEFAULT=0 to highest array element of UserColor()
    SendScintillaMsg pSciWndData,%SCI_STYLESETFORE,i,UserColor(i)                         'Set the text color
  Next i
  '
  SendScintillaMsg pSciWndData,%SCI_SETUSETABS,0,0                                        'Replace TABs by Space characters
  SendScintillaMsg pSciWndData,%SCI_SETTABWIDTH,2,0                                       'A TAB has a width of 2 spaces
  SendScintillaMsg pSciWndData,%SCI_SETINDENT,2,0                                         'An indention consist of 2 spaces
End Sub
'*************************************************************************************************************************************
Function GetCurrentLine() As Dword
  'Retrieves the line number of the line which contains the caret.
  Function=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0),0)
End Function
'*************************************************************************************************************************************
Sub ToggleSub(ByVal LineNumber As Long)
  'Toggles the Sub/Function given by the line number. Any line number in a sub is legal.
  'The function returns the current line number after toggling.
  Static FirstLine As Long
  '
  If (SendScintillaMsg(pSciWndData,%SCI_GETFOLDLEVEL,LineNumber,0) And %SC_FOLDLEVELHEADERFLAG)=0 Then 'We are not in a head line
    FirstLine=SendScintillaMsg(pSciWndData,%SCI_GETFOLDPARENT,LineNumber,0)  'Get the number of the head line of the sub
    If FirstLine<1 Then 'GoTo DoneToggleSub                                  '-1: No sub head found, we are in the head of the listing
      FirstLine=0
      SendScintillaMsg pSciWndData,%SCI_SETFOLDLEVEL,FirstLine,%SC_FOLDLEVELHEADERFLAG 'Line 0 acts as a head line as it whould be a Sub
    End If   
  Else
    FirstLine=LineNumber
  End If
  'SetWindowText hWndMain,"Debug:"+Str$(lineNumber)
  SendScintillaMsg pSciWndData,%SCI_TOGGLEFOLD,FirstLine,0      'Toggle the sub
  If FirstLine<>LineNumber Then SendScintillaMsg pSciWndData,%SCI_GOTOLINE,FirstLine,0    'Set the caret to the head line of the sub
  DoneToggleSub:
End Sub
'*************************************************************************************************************************************
Sub ToggleSubsBelow(ByVal LineNumber As Long)
  'Toggles the current Sub/Function and all below. The current Sub decides whether the other Subs are to close or to open.
  Register i As Long
  Static FoldState As Long,FirstLine As Long
  '
  'Toggle the first sub and get the toggle state ofter done:
  If (SendScintillaMsg(pSciWndData,%SCI_GETFOLDLEVEL,LineNumber,0) And %SC_FOLDLEVELHEADERFLAG) Then 'We are in a head line
    FirstLine=LineNumber
  Else                                                                       'We are in the mid or at the end of the sub
    FirstLine=SendScintillaMsg(pSciWndData,%SCI_GETFOLDPARENT,LineNumber,0)  'Get the number of the head line of the sub
  End If
  '
  If FirstLine<1 Then                                                               'We are in the head of the listing
    FirstLine=0
    SendScintillaMsg pSciWndData,%SCI_SETFOLDLEVEL,FirstLine,%SC_FOLDLEVELHEADERFLAG 'Line 0 acts as a head line as it whould be a Sub
  End If
  If FirstLine<>LineNumber Then SendScintillaMsg pSciWndData,%SCI_GOTOLINE,FirstLine,0   'We must set the caret to the head of the sub
  SendScintillaMsg pSciWndData,%SCI_TOGGLEFOLD,FirstLine,0                               'Toggle the sub
  FoldState=SendScintillaMsg(pSciWndData,%SCI_GETFOLDEXPANDED,FirstLine,0)               'Determine whether the sub is expanded or not
  '
  'Now the rest:
  SetCursor LoadCursor(%NULL,ByVal %IDC_APPSTARTING)   'For very long listings the following loop needs a bit time, show hourglass mouse
  For i=LineNumber To SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0)
    If (SendScintillaMsg(pSciWndData,%SCI_GETFOLDLEVEL,i,0) And %SC_FOLDLEVELHEADERFLAG) Then 'We are in a head line
      If SendScintillaMsg(pSciWndData,%SCI_GETFOLDEXPANDED,i,0)<>FoldState Then 'State different from first sub, toggle
        SendScintillaMsg pSciWndData,%SCI_TOGGLEFOLD,i,0
      End If
    End If
  Next i
  SetCursor LoadCursor(%NULL,ByVal %IDC_ARROW)   'Show standard mouse
End Sub
'*************************************************************************************************************************************
Sub MakeTextRangeVisible(ByVal dwStartPos As Dword,ByVal dwEndPos As Dword)
  'Called after SCN_NEEDSHOWN notification: One or more lines are currently invisible and should be made visible
  'Used global variables: pSciWndData
  Static lCurLine As Long,lLastLine As Long
  lLastLine=Max(0,SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndPos,0))
  For lCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartPos,0) To lLastLine
    SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,lCurLine,0    'Open the sub containing this line if necessary
  Next lCurLine
  '
  'The range told by SCN_NEEDSHOWN isn't perfectly
  'Before we call SCI_ENSUREVISIBLE for the last line we check whether this is/was a head line
  If (SendScintillaMsg(pSciWndData,%SCI_GETFOLDLEVEL,lLastLine,0) And %SC_FOLDLEVELHEADERFLAG) Then 'Head line of a sub
    If SendScintillaMsg(pSciWndData,%SCI_GETFOLDEXPANDED,lLastLine,0)=0 Then ToggleSub(lLastLine) 'Open the Sub if closed
  Else
    SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,lLastLine,0    'Open the sub containing this line if necessary
  End If
End Sub
'*************************************************************************************************************************************
Sub BlockComment(ByVal Amount As Long)
  'Comments/uncomments the lines of the currently selected text. If Amount>0 it's commented 1 postition to right, else uncommented.
  'Uncommenting isn't done if one of the lines doesnt start with a comment stroke character which can be removed.
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwStartSelection As Dword,dwEndSelection As Dword
  Static dwCurLine As Dword,dwPosFirstChar As Dword
  Static bFirstChar As Byte,wStrokePlusNul As Word
  '
  dwStartSelection=SendScintillaMsg(pSciWndData,%SCI_GETANCHOR,0,0)
  dwEndSelection=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)
  If SendScintillaMsg(pSciWndData,%SCI_GETCOLUMN,dwEndSelection,0)=0 Then 'If end of selection is start of line
    Decr dwEndSelection
  End If
  '
  If Amount>0 Then  'Comment by inserting a stroke character
    wStrokePlusNul=MakWrd(&H27,0)  'Same as "'"+$Nul
    For dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartSelection,0) To SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndSelection,0)
      dwPosFirstChar=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwCurLine,0)
      SendScintillaMsg pSciWndData,%SCI_INSERTTEXT,dwPosFirstChar,ByRef wStrokePlusNul
      Incr dwEndSelection  'Update end of selection
    Next dwCurLine
  Else 'Indent to left by removing existing space characters
    'First check whether *all* lines start with a stroke character
    For dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartSelection,0) To SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndSelection,0)
      dwPosFirstChar=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwCurLine,0)
      bFirstChar=SendScintillaMsg(pSciWndData,%SCI_GETCHARAT,dwPosFirstChar,0)  'Get the first character of the line
      If bFirstChar<>&H27 Then Exit For 'Cancel if first character isn't a stroke
    Next dwCurLine
    If bFirstChar=&H27 Then 'If all lines start with a stroke character
      bFirstChar=0   'This we use as a NULL terminated "string" with zero length
      SendScintillaMsg pSciWndData,%SCI_HIDESELECTION,%TRUE,0  'No selection updates for the following action
      For dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartSelection,0) To SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndSelection,0)
        dwPosFirstChar=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwCurLine,0)
        SendScintillaMsg pSciWndData,%SCI_SETSEL,dwPosFirstChar,dwPosFirstChar+1   'Select the first character of the line
        SendScintillaMsg pSciWndData,%SCI_REPLACESEL,0,ByRef bFirstChar  'Replace the selection by text with zero length
        Decr dwEndSelection  'Update end of selection
      Next dwCurLine
      SendScintillaMsg pSciWndData,%SCI_HIDESELECTION,%FALSE,0  'All done, show selection
    End If
  End If
  SendScintillaMsg pSciWndData,%SCI_SETSEL,dwStartSelection,dwEndSelection   'Restore the selection
End Sub
'*************************************************************************************************************************************
Sub BlockIndent(ByVal Amount As Long)
  'Indents the lines of the currently selected text. If Amount>0 it's indented 1 postition to right, else to left.
  'Indenting to left isn't done if one of the lines doesnt start with a space character which can be removed.
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwStartSelection As Dword,dwEndSelection As Dword
  Static dwCurLine As Dword,dwPosFirstChar As Dword
  Static bFirstChar As Byte,wSpacePlusNul As Word
  '
  dwStartSelection=SendScintillaMsg(pSciWndData,%SCI_GETANCHOR,0,0)
  dwEndSelection=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)
  If SendScintillaMsg(pSciWndData,%SCI_GETCOLUMN,dwEndSelection,0)=0 Then 'If end of selection is start of line
    Decr dwEndSelection
  End If
  '
  If Amount>0 Then  'Indent to right by inserting a space character
    wSpacePlusNul=MakWrd(&H20,0)  'Same as " "+$Nul
    For dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartSelection,0) To SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndSelection,0)
      dwPosFirstChar=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwCurLine,0)
      SendScintillaMsg pSciWndData,%SCI_INSERTTEXT,dwPosFirstChar,ByRef wSpacePlusNul
      Incr dwEndSelection  'Update end of selection
    Next dwCurLine
  Else 'Indent to left by removing existing space characters
    'First check whether *all* lines start with a space character
    For dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartSelection,0) To SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndSelection,0)
      dwPosFirstChar=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwCurLine,0)
      bFirstChar=SendScintillaMsg(pSciWndData,%SCI_GETCHARAT,dwPosFirstChar,0)  'Get the first character of the line
      If bFirstChar<>&H20 Then Exit For 'Cancel if first character isn't a space
    Next dwCurLine
    If bFirstChar=&H20 Then 'If all lines start witrh a space character
      bFirstChar=0   'This we use as a NULL terminated "string" with zero length
      SendScintillaMsg pSciWndData,%SCI_HIDESELECTION,%TRUE,0  'No selection updates for the following action
      For dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwStartSelection,0) To SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,dwEndSelection,0)
        dwPosFirstChar=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwCurLine,0)
        SendScintillaMsg pSciWndData,%SCI_SETSEL,dwPosFirstChar,dwPosFirstChar+1   'Select the first character of the line
        SendScintillaMsg pSciWndData,%SCI_REPLACESEL,0,ByRef bFirstChar  'Replace the selection by text with zero length
        Decr dwEndSelection  'Update end of selection
      Next dwCurLine
      SendScintillaMsg pSciWndData,%SCI_HIDESELECTION,%FALSE,0  'All done, show selection
    End If
  End If
  SendScintillaMsg pSciWndData,%SCI_SETSEL,dwStartSelection,dwEndSelection   'Restore the selection
End Sub
'*************************************************************************************************************************************
Function GetCurResFile(szResFile As Asciiz) As Dword
  'Retrieves the current *.res resource file given in the currently loaded listing (PowerBasic) or given in the current
  'Project settings (FreeBasic).
  'For PowerBasic: This function searches the first 300 lines of the listing for the PowerBasic statement #resource (or $resource).
  '                If the statement isn't found in this part of the listing the function returns 0 (error) and shows an error
  '                MessageBox. If the statement is found the function copies the *.res filename of the *.pbr filename given in
  '                #resource/$resource with full path. The return value contains the length of the returned string. The function
  '                handles simple quoted filenames only such as #RESOURCE="test.pbr". Statements such as
  '                #RESOURCE="test"+Chr$(21)+".res" are not interpreted correctly.
  'Used global variables: pSciWndData,hWndMain,szCurDir,szCurFile
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwCurLine As Dword,dwLenCurLine As Dword,pByte As Byte Ptr,dwAdrLine As Dword
  Static szUsedResFile As Asciiz*%MAX_PATH*2,szBuffer As Asciiz*%MAX_PATH
  Static dwAdrStatement As Dword,dwAdrStart As Dword,dwAdrEnd As Dword,dwAdrLineEnd As Dword,hFile As Dword,dwTemp As Dword

  'In PowerBasic we retrieve the resource filename from listing, in FreeBasic we can skip this step:
  If dwCompilerType<>%CMPTYPE_POWERBASIC Then
    If Len(ProjectSettings.szResFile)=0 Then
      szBuffer=Left$(szCurFile,InStr(-1,szCurFile,"."))+"res"
      If MessageBox(hWndMain,"No Resource filename specified. Use this filename?"+$CR+$CR+szBuffer,"",_
                    %MB_ICONQUESTION Or %MB_YESNO)=%IDYES Then
        szUsedResFile=szBuffer
        GoTo GetCurResFileCreate
      Else
        Function=0             'Return error
        GoTo GetCurResFileDone
      End If
    Else
      szUsedResFile=ProjectSettings.szResFile
      GoTo GetCurResFileCreate
    End If
  End If
  '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  'PowerBasic only: Retrieve the resource filename from listing
  '
  szUsedResFile=""
  dwAdrStatement=0
  '
  For dwCurLine=0 To 299  'First 300 lines
    dwLenCurLine=SendScintillaMsg(pSciWndData,%SCI_LINELENGTH,dwCurLine,0)
    If dwLenCurLine>16 Then '16: Len(#resource="a.res")=17 - skip lines which are too short
      dwAdrLine=GlobalAlloc(%GMEM_FIXED,dwLenCurLine)
      dwAdrLineEnd=dwAdrLine+dwLenCurLine-1
      SendScintillaMsg pSciWndData,%SCI_GETLINE,ByVal dwCurLine,ByVal dwAdrLine
      For pByte=dwAdrLine To dwAdrLineEnd-17  '-17: Len(#resource="a.res")=17
        Select Case @pByte
        Case &H27             '&H27= ' (comment stroke)
          Exit For:Exit For   'Cancel
        Case &H23,&H24        '&H23="#", &H24="$"
          If UCase$(Peek$(pByte+1,8))="RESOURCE" Then     '8=Len("resource")
            dwAdrStatement=pByte+9
            Exit,Exit         'We have done the search, leave the FOR-NEXT loops
          End If
        End Select
      Next pByte
      GlobalFree dwAdrLine
    End If
  Next dwCurLine
  '
  If dwAdrStatement=0 Then 'No #resource/$resource statement found
    GlobalFree dwAdrLine   'Free the line buffer
    szResFile=""           'Return an empty string
    MessageBox hWndMain,"No #Resource or $Resource statement found in the first 300 source code lines.","",%MB_ICONSTOP
    Function=0             'Return error
    GoTo GetCurResFileDone
  End If
  '
  'Watch: Newer PowerBasic versions have expanded #Resource statements such as:
  '#RESOURCE BITMAP,   ResID, "filespec.BMP"
  '#RESOURCE ICON,     ResID, "filespec.ICO"
  '#RESOURCE MANIFEST,     1, "filespec.XML"
  '#RESOURCE RCDATA,   ResID, "filespec.DAT"
  '#RESOURCE STRING,   ResID, "YourWideText"$$ [,LangID]
  '#RESOURCE TYPELIB,      1, "filespec.TLB"
  '#RESOURCE WAVE,     ResID, "filespec.WAV"
  '#RESOURCE VERSIONINFO <<block>>
  '#RESOURCE RES, "filespec.RES"
  '#RESOURCE PBR, "filespec.PBR"

  dwAdrStart=0
  dwAdrEnd=0
  For pByte=dwAdrStatement To dwAdrLineEnd   'Find starting and ending " ($Dqout)
    Select Case @pByte
      Case &H27             '&H27= ' (comment stroke)
      Exit For              'Cancel
    Case &H22               '&H22 = " ($Dqout)
      If dwAdrStart=0 Then
        dwAdrStart=pByte+1
      Else
        dwAdrEnd=pByte
        Exit For            'Done
      End If
    End Select
  Next pByte
  If dwAdrStart<>0 And dwAdrEnd>dwAdrStart Then
    szUsedResFile=Peek$(dwAdrStart,dwAdrEnd-dwAdrStart)             'Now we have the PBR filename, for example TEST.PBR
    GlobalFree dwAdrLine                                            'Free the line buffer
  Else
    GlobalFree dwAdrLine  'Free the line buffer
    szResFile=""          'Return an empty string
    MessageBox hWndMain,"#Resource/$Resource statement incorrect or has an invalid format for the editor."+Chr$(13)+_
                        "Use a simple quoted filename please, such as:"+Chr$(13,13)+_
                        "#Resource="+$DQ+"MyTestResource.pbr"+$DQ+Chr$(13)+_
                        "or"+Chr$(13)+_
                        "$RESOURCE="+$DQ+"Test.pbr"+$DQ+Chr$(13,13)+_
                        "For example the following format is not supported:"+Chr$(13,13)+_
                        "#Resource="+$DQ+"MyTe"+$DQ+"+Chr$(&H73)+"+$DQ+"t.pbr"+$DQ,"",%MB_ICONSTOP
    Function=0            'Return error
    GoTo GetCurResFileDone
  End If
  'MsgBox szUsedResFile
  szUsedResFile=Left$(szUsedResFile,Len(szUsedResFile)-3)+"res"          '*.pbr ---> *.res
  szUsedResFile=szCurDir+szUsedResFile                                   'Add path
  '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  'Now check whether the resource file exists and create an empty new one if not:
  GetCurResFileCreate:
  '
  hFile=lopen(szUsedResFile,%OF_READ)                             'Does the file exist?
  lclose hFile
  If hFile=%INVALID_HANDLE_VALUE Then                             'The file doesn't exist
    If MessageBox(hWndMain,"The resource file"+Chr$(13)+szUsedResFile+Chr$(13)+"doesn't exist."+Chr$(13,13)+_
                        "Create this file as a new empty resource file?",$APP_NAME,%MB_ICONQUESTION Or %MB_YESNO)=%IDYES Then
      dwTemp=CreateEmptyResFile(szUsedResFile)                    'Create new empty resource file
      If dwTemp=0 Then                                            'File successfull created
        szResFile=szUsedResFile                                   'Copy to target string
        Function=Len(szResFile)                                   'Return lenth of resource file name
      Else
        Function=0                                                'Return error
      End If
    Else
      Function=0                                                  'Return error
    End If
  Else                                                            'The resource file exists
    szResFile=szUsedResFile                                       'Copy to target string
    Function=Len(szResFile)                                       'Return lenth of resource file name
  End If
  '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  GetCurResFileDone:
  'MsgBox "--->"+szResFile+"<---",0,"Debug"
End Function
'*************************************************************************************************************************************
Function CreateEmptyResFile(szResFileName As Asciiz) As Dword
  'Creates an empty 32 bit binary resource file (*.res), which a resource editor can load. The header of a 32 bit resource file is
  'simply an empty resource record of 32 bytes length. In the opposite an empty 16 bit resource file has zero length.
  'Returns 0 if error
  'The function shows a MessageBox if any error occurs.
  'Global variables: hWndMain
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static hFile As Dword,dwRetVal As Dword,sBuffer As String
  
  dwRetVal=0

  'File extension of the .RES file correct?
  If UCase$(Right$(szResFileName,4))<>".RES" Then
    MessageBox hWndMain,"The Resource file to create has an invalid extension (.RES expected)"+Chr$(13)+szResFileName,"",%MB_ICONSTOP
    GoTo DoneCreateEmptyResFile
  End If
  '
  'Does the .RES file just exist?
  hFile=lopen(szResFileName,%OF_READ)
  lclose hFile
  If hFile<>%INVALID_HANDLE_VALUE Then                'File exists
    If MessageBox(hWndMain,"The resource file"+Chr$(13)+szResFileName+Chr$(13)+"just exists."+Chr$(13,13)+"Really overwrite it?",_
                  $APP_NAME,%MB_ICONQUESTION Or %MB_YESNO)=%IDNO Then GoTo DoneCreateEmptyResFile
    MoveFile szResFileName,szResFileName+".bak"   'better we rename the existing file, than simply overwriting it
  End If
  '
  'Create a new empty resource file file or overwrite existing file:
  hFile=lcreat(szResFileName,0)
  sBuffer=Chr$(&H00,&H00,&H00,&H00,&H20,&H00,&H00,&H00,&HFF,&HFF,&H00,&H00,&HFF,&HFF,&H00,&H00,_
               &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00)
  If lwrite(hFile,ByVal StrPtr(sBuffer),Len(sBuffer))=Len(sBuffer) Then 'Write the 32 bit *.res file header record
    lclose hFile
  Else
    lclose hFile
    dwRetVal=1                                       'File write error
    MoveFile szResFileName+".bak",szResFileName    'Try to replace the (insuccessfull) created new file by the original file
    MessageBox hWndMain,"Error while creating the empty 32 bit resource file"+Chr$(13)+szResFileName,"",%MB_ICONSTOP
  End If
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneCreateEmptyResFile:
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Sub AutoCaseCorrector()
  'Autocorrects the (mixed) case of the keyword one position left from cursor position. We use the Scintilla style bits
  'to determine whether we have a keyword/constant or not. The routine must be called after notification SCN_UPDATEUI.
  'Above it must be called after the user inserts a hard return (SCN_CHARADDED with "If @pNMHdr.ch=&H0A Or @pNMHdr.ch=&H0D").
  '
  'Used global variables: sBasicKeyWords,sBasicKeyWords,sBasicKeyWordsLCase,sBasicKeyWordsLCase,pSciWndData
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwCurPos As Dword,TxtRange As TextRange,dwPosInList As Dword,dwCursorPos As Dword,dwCursorShift As Dword
  Static szCurKeyword As Asciiz*255,szCurKeywordCorrectCase As Asciiz*255
  Static CurStyle As Long,NextStyle As Long,lLenKeyword As Long
  '
  dwCurPos=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)
  If dwCurPos<>SendScintillaMsg(pSciWndData,%SCI_GETANCHOR,0,0) Then GoTo CaseCorrectorDone  'Do nothing if any selection exists
  If SendScintillaMsg(pSciWndData,%SCI_GETCHARAT,dwCurPos-1,0)=10 Then                       'Special case: Line change
    If dwCurPos>3 Then dwCursorShift=3  'We check the position left from cursor with line change 13+10 between 
  Else
    If dwCurPos>2 Then dwCursorShift=2  'We check the position left from cursor with one character between 
  End If
  dwCurPos=dwCurPos-dwCursorShift
  '
  CurStyle=SendScintillaMsg(pSciWndData,%SCI_GETSTYLEAT,dwCurPos,0) And &B00011111 'Style of the preceding character
  NextStyle=SendScintillaMsg(pSciWndData,%SCI_GETSTYLEAT,dwCurPos+1,0) And &B00011111 'Style of the following character
  If CurStyle=NextStyle Then GoTo CaseCorrectorDone          'We are not one position right from keyword end (or constant and so on)
  Select Case CurStyle
  Case %SCE_B_APIKEYWORD,%SCE_B_BASICKEYWORD,%SCE_B_CONSTANT
  Case Else
    GoTo CaseCorrectorDone
  End Select
  '
  TxtRange.chrg.cpMin=SendScintillaMsg(pSciWndData,%SCI_WORDSTARTPOSITION,dwCurPos,%TRUE)
  TxtRange.chrg.cpMax=SendScintillaMsg(pSciWndData,%SCI_WORDENDPOSITION,dwCurPos,%TRUE)
  lLenKeyword=TxtRange.chrg.cpMax-TxtRange.chrg.cpMin
  'SetWindowText hWndMain,"Start:"+Str$(TxtRange.chrg.cpMin)+", End:"+Str$(TxtRange.chrg.cpMax)
  
  If lLenKeyword<1 Then GoTo CaseCorrectorDone
  If lLenKeyword>SizeOf(szCurKeyword) Then GoTo CaseCorrectorDone
  '
  dwCursorPos=TxtRange.chrg.cpMin+lLenKeyword+dwCursorShift-(TxtRange.chrg.cpMax-dwCurPos)
  'SetWindowText hWndMain,"Pos in keyword:"+Str$(dwPosInKeyword)
  '
  TxtRange.lpstrText=VarPtr(szCurKeyword)
  SendScintillaMsg pSciWndData,%SCI_GETTEXTRANGE,0,ByVal VarPtr(TxtRange)
  'SetWindowText hWndMain,"Current keyword: <"+szCurKeyword+">"
  '
  Select Case CurStyle
  Case %SCE_B_CONSTANT
    szCurKeywordCorrectCase=UCase$(szCurKeyword)
  Case %SCE_B_BASICKEYWORD
    dwPosInList=InStr(sBasicKeyWordsLCase," "+LCase$(szCurKeyword)+" ")
    If dwPosInList Then szCurKeywordCorrectCase=Mid$(sBasicKeyWords,dwPosInList,lLenKeyword)
  Case %SCE_B_APIKEYWORD
    dwPosInList=InStr(sApiKeyWordsLCase," "+LCase$(szCurKeyword)+" ")
    If dwPosInList Then szCurKeywordCorrectCase=Mid$(sApiKeyWords,dwPosInList,lLenKeyword)
  End Select
  '
  If szCurKeyword<>szCurKeywordCorrectCase Then
    'SetWindowText hWndMain,"<"+szCurKeyword+"> ---> <"+szCurKeywordCorrectCase+"> ("+Str$(TxtRange.chrg.cpMin)+"-"+Str$(TxtRange.chrg.cpMax)+", Len:"+Str$(lLenKeyword)+")"
    SendScintillaMsg pSciWndData,%SCI_SETTARGETSTART,TxtRange.chrg.cpMin,0
    SendScintillaMsg pSciWndData,%SCI_SETTARGETEND,TxtRange.chrg.cpMax,0
    SendScintillaMsg pSciWndData,%SCI_REPLACETARGET,lLenKeyword,ByRef szCurKeywordCorrectCase
  End If
  '
  CaseCorrectorDone:
End Sub
'*************************************************************************************************************************************
Function GetCurrentKeyWordForHelp(szBuffer As Asciiz) As Dword
  'Retrieves the keyword at current position into szBuffer. Returns TRUE if the found keyword is in the Basic keyword list.
  'Called before opening WinHelp.
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwCurPos As Dword,TxtRange As TextRange,sBuffer As String,szUcaseBuffer As Asciiz*255
  '
  dwCurPos=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)

  TxtRange.chrg.cpMin=SendScintillaMsg(pSciWndData,%SCI_WORDSTARTPOSITION,dwCurPos,0)
  TxtRange.chrg.cpMax=SendScintillaMsg(pSciWndData,%SCI_WORDENDPOSITION,dwCurPos,0)
  TxtRange.lpstrText=VarPtr(szBuffer)
  SendScintillaMsg pSciWndData,%SCI_GETTEXTRANGE,0,ByVal VarPtr(TxtRange)
  szBuffer=RTrim$(szBuffer,Any " ;,-:+*#\/=)([]{}´`<>|~"+$CR+$LF)  'Remove last character if not part of the keyword

  szUcaseBuffer=UCase$(szBuffer)
'  If Peek(VarPtr(szBuffer))=&H25 Then 'Chr$(&H25)="%"
'    If szUcaseBuffer<>"%DEF" Then 
'      szBuffer=Mid$(szBuffer,2)
'      szUcaseBuffer=Mid$(szUcaseBuffer,2)
'    End If
'  End If

  If dwCompilerType=%CMPTYPE_POWERBASIC Then 'PowerBasic: Convert renamed API functions to their true name
    If szUcaseBuffer="HREAD" Then        'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_hread"
    ElseIf szUcaseBuffer="HWRITE" Then   'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_hwrite"
    ElseIf szUcaseBuffer="LCLOSE" Then   'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_lclose"
    ElseIf szUcaseBuffer="LCREAT" Then   'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_lcreat"
    ElseIf szUcaseBuffer="LLSEEK" Then   'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_llseek"
    ElseIf szUcaseBuffer="LOPEN" Then    'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_lopen"
    ElseIf szUcaseBuffer="LREAD" Then    'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_lread"
    ElseIf szUcaseBuffer="LWRITE" Then   'API functions starting with "_" are renamed in PowerBasic
      szBuffer="_lwrite"
    End If
  End If
'MsgBox szBuffer
  If InStr(sBasicKeyWordsLCase,LCase$(Trim$(szBuffer)))=0 Then 'Is the keyword not in the Basic keyword list?
    Select Case dwCompilerType
    Case %CMPTYPE_POWERBASIC                         'PowerBasic: Check for PowerBasic constant
      If Left$(szBuffer,1)="$" Then                  'Example: $NUL,$TAB...
        Function=1                                   'It's a Basic keyword
      ElseIf Left$(szBuffer,1)="%" Then              'examples: %ERR_..., %DEF, %CYAN or %WM_COMMAND, %ES_LEFT
        If Left$(szBuffer,5)="%ERR_" Then
          Function=1                                 'It's a Basic keyword
        ElseIf Left$(szBuffer,10)="%VARCLASS_" Then  'examples: %VARCLASS_BYT, %VARCLASS_STR
          Function=1                                 'It's a Basic keyword
        ElseIf Left$(szBuffer,4)="%PB_" Then         'examples: %PB_WIN32, %PB_EXE
          Function=1                                 'It's a Basic keyword
        ElseIf Left$(szBuffer,4)="%VT_" Then         'examples: %VT_ARRAY, %VT_LPWSTR
          Function=1                                 'It's a Basic keyword
        Else
          szBuffer=Mid$(szBuffer,2)                  'Remove the "%" for the following check
          Select Case szBuffer
          Case "DEF","DWL_MSGRESULT","BLACK","BLUE","CYAN","GRAY","GREEN","LTGRAY","MAGENTA","RED","WHITE","YELLOW"
            szBuffer="%"+szBuffer                    'Reset the "%" for the keyword
            Function=1                               'It's a Basic keyword
          Case Else
            Function=0                               'It's an API keyword
          End Select
        End If
      Else
        Function=0                                   'It's an API keyword
      End If
    Case Else                                        '%CMPTYPE_FREEBASIC,%CMPTYPE_UNKNOWN
      Function=0                                     'It's an API keyword
    End Select    
  Else
    Function=1                                     'It's a Basic keyword
  End If                                           'Is the keyword not in the Basic keyword list? - Check for PB constant.
End Function
'*************************************************************************************************************************************
Function GetCurExeFile(szExeFile As Asciiz) As Dword
  'For PowerBasic only: Retrieves the executable to create by the current listing.
  'This function searches the first 100 lines of the listing for the PowerBasic statement #compile (or $compile).
  'If the statement isn't found in this part of the listing the function returns 0. szExeFile is set to ""
  'If the executable to create is a DLL the function returns 1. szExeFile contains the DLL filename
  'If the executable to create is a EXE the function returns 2. szExeFile contains the EXE filename
  'The function handles simple quoted filenames only such as #COMPILE="test.exe". Statements such as #RESOURCE="test"+Chr$(21)+".exe"
  'are not interpreted correctly.
  'Used global variables: pSciWndData
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwCurLine As Dword,dwLenCurLine As Dword,pszLine As Asciiz Ptr,szLine As Asciiz*%MAX_PATH*2,dwBuffer As Dword
  Static dwRetVal As Dword
  
  dwRetVal=0  'Set the function return value initially to "No compile statement found"
  szLine=""
  For dwCurLine=0 To 99  'First 100 lines
    dwLenCurLine=SendScintillaMsg(pSciWndData,%SCI_LINELENGTH,dwCurLine,0)
    If dwLenCurLine>12 Then '11=Len("COMPILE EXE") - skip lines which are too short
      pszLine=GlobalAlloc(%GMEM_FIXED,dwLenCurLine)
      SendScintillaMsg pSciWndData,%SCI_GETLINE,ByVal dwCurLine,ByVal pszLine
      dwBuffer=InStr(@pszLine,"'")                         'Comment in?
      If dwBuffer Then @pszLine=Left$(@pszLine,dwBuffer-1) 'Delete comment
      dwBuffer=InStr(UCase$(@pszLine),"COMPILE")           'Compile statement in?
      If dwBuffer Then
        szLine=@pszLine
        GlobalFree pszLine
        Exit For         'We have done the search, leave the FOR-NEXT loop
      End If
      GlobalFree pszLine
    End If
  Next dwCurLine
  '
  If szLine="" Then        'No #compile/$compile statement found
    szExeFile=""           'Return an empty string
    dwRetVal=0             'Return no compile statement found
  Else
    dwBuffer=InStr(szLine,$DQ)                        'Is there a EXE/DLL filename specified in the line (double quots)?
    If dwBuffer Then                                  'There is a filename in    
      szExeFile=Mid$(szLine,dwBuffer+1)  
      szExeFile=Left$(szExeFile,InStr(-1,szExeFile,$DQ)-1)
      If InStr(UCase$(Left$(szLine,dwBuffer)),"DLL") Then
        dwRetVal=1                        'Return target is DLL
      Else
        dwRetVal=2                        'Return target is EXE
      End If
    Else                                   'There is no filename in    
      szExeFile=""                         'Return an empty string
      If InStr(UCase$(szLine),"DLL") Then
        dwRetVal=1                         'Return target is DLL
      Else
        dwRetVal=2                         'Return target is EXE
      End If
    End If
  End If
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Function CompileFreeBasic(ByVal dwMode As Dword) As Dword
  'Compiles the current listing given by szCurFile.
  'dwMode: If 0 the funtion compiles only. If 1 the function compiles and if sucsessfull it starts the resulting program if EXE
  'Return values:
  '   0 if sucsessfull 
  '   1 if error staring compiler'
  '   2 Compiling error (error in sourcecode)
  'Shows the result in a MessageBox if not Run and successfull
  'Used global variables: szCurFile,szCurDir,szIncDir,szCompilerFile,hWndMain,pSciWndData
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static ProcessInfo As PROCESS_INFORMATION,StartInfo As STARTUPINFO,szCmdLine As Asciiz*%MAX_PATH*2
  Static szIncDirLocal As Asciiz*%MAX_PATH,szCurFileWithoutPath As Asciiz*%MAX_PATH
  Static sSwitchTarget As String,sSwitchTargetName As String,sResourceFile As String
  Static dwProcessExitCode As Dword,hConsoleOutput As Dword,sBuffer As String
  Static hOutputPipe As Dword,hInputPipe As Dword,SecurityAttributes As SECURITY_ATTRIBUTES,dwBytesGot As Dword
  Static sCompilerOutput As String
  Static dwLine As Dword,dwStartPos As Dword
  Static dwBuffer As Dword,szBuffer As Asciiz*%MAX_PATH,hProcessQuery As Dword,dwTimeOut As Dword,dwRetVal As Dword
  
  dwRetVal=0       'Set return value initial to "Success"
  hProcessQuery=0  'Invalidate Process handle used for query action

  szIncDirLocal=szIncDir
  If Len(szIncDir)=0 Then
    MessageBox hWndMain,"No valid INCLUDE directory set (see menu "+$DQ+"Options"+$DQ+").","Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  If InStr(szIncDirLocal," ") Then szIncDirLocal=$DQ+szIncDirLocal+$DQ 'Add quotes if there are spaces in filename
  '  
  If GetFileAttributes(szCompilerFile)=-1 Then
    MessageBox hWndMain,"Couldn't find compiler. Check compiler path+filename (see menu "+$DQ+"Options-->General settings"+$DQ+").","Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  '
  dwBuffer=InStr(-1,szCurFile,"\")+1 'Path information in current source file?
  If dwBuffer>1 Then szCurFileWithoutPath=Mid$(szCurFile,dwBuffer)  'Remove path
  If szCurFileWithoutPath="" Then
    MessageBox hWndMain,"Illegal or no filename for the current listing."+Chr$(13)+szCurFile,"Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  If InStr(szCurFileWithoutPath," ") Then szCurFileWithoutPath=$DQ+szCurFileWithoutPath+$DQ 'Add quotes if there are spaces in filename
  '
  'Because we use the listing filename without path we must set the current directory. Above it's important to set
  'the current directory because the PB compiler writes the log file always into the current directory, not into
  'another one.
  SetCurrentDirectory Left$(szCurFile,InStr(-1,szCurFile,"\"))
  '
  'No create the command line depending on the user settings:
  Select Case ProjectSettings.dwTargetFileType
  Case %TARGET_WIN32_OBJ
    sSwitchTarget="-c"          'Compile only, do not link 
  Case %TARGET_WIN32_LIB
    sSwitchTarget="-lib"        'Create a static library
  Case %TARGET_WIN32_DLL
    sSwitchTarget="-dll"        'Create a DLL, including the import library
  Case %TARGET_WIN32_GUI
    sSwitchTarget="-s gui"      'Set subsystem (gui, console) 
  Case Else                     '%TARGET_WIN32_CONSOLE
    sSwitchTarget="-s console"  'Set subsystem (gui, console) 
  End Select
  '
  If Len(ProjectSettings.szTargetFilename) Then
    If InStr(ProjectSettings.szTargetFilename," ") Then                  'Add quotes if there are spaces in filename
      sSwitchTargetName=" -x "+$DQ+ProjectSettings.szTargetFilename+$DQ  '-x: Set executable/library name 
    Else
      sSwitchTargetName=" -x "+ProjectSettings.szTargetFilename          '-x: Set executable/library name 
    End If
  Else
    sSwitchTargetName=""
  End If
  '
  If Len(ProjectSettings.szResFile) Then
    If InStr(ProjectSettings.szResFile," ") Then                  'Add quotes if there are spaces in filename
      sResourceFile=" "+$DQ+ProjectSettings.szResFile+$DQ
    Else
      sResourceFile=" "+ProjectSettings.szResFile
    End If
  Else
    sResourceFile=""
  End If
  '
  '-v: verbous, -i: include file
  szCmdLine=" "+sSwitchTarget+" -v -i "+szIncDirLocal+sSwitchTargetName+" "+szCurFileWithoutPath+sResourceFile
  'szCmdLine=" "+sSwitchTarget+" -v -i "+szIncDirLocal+sSwitchTargetName+" "+Extract$(szCurFileWithoutPath,$Nul)+sResourceFile
  '
  'We let the standard output write to a pipe:
  SecurityAttributes.nLength=SizeOf(SECURITY_ATTRIBUTES)
  SecurityAttributes.bInheritHandle = 1 ' TRUE
  If CreatePipe(hInputPipe,hOutputPipe,SecurityAttributes,ByVal 0)=0 Then
    'Function = -2
    'Exit Function
  End If
  '
  StartInfo.cb=SizeOf(StartInfo)
  StartInfo.dwFlags=%STARTF_USESTDHANDLES Or %STARTF_USECOUNTCHARS Or %STARTF_USESHOWWINDOW
  StartInfo.wShowWindow=%SW_HIDE
  StartInfo.dwXCountChars=80
  StartInfo.dwYCountChars=25
  StartInfo.hStdInput=0
  StartInfo.hStdOutput=hOutputPipe
  StartInfo.hStdError=hOutputPipe
  If CreateProcess(szCompilerFile,szCmdLine,ByVal 0,ByVal 0,%TRUE,%HIGH_PRIORITY_CLASS,ByVal 0,ByVal 0,StartInfo,ProcessInfo)=0 Then
    FreeConsole
    MessageBox hWndMain,"Application:"+$CR+szCompilerFile+$CR+$CR+"Command line:"+$CR+szCmdLine,"Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  '
  'Wait until the compiler has done it's job:
  hProcessQuery=OpenProcess(%PROCESS_QUERY_INFORMATION,0,ProcessInfo.dwProcessId)
  SetCursor LoadCursor(%NULL,ByVal %IDC_WAIT)  'Wait mouse
  dwTimeOut=timeGetTime()+dwCompileTimeout*1000 'Timeout (dwCompileTimeout holds the user defined value in seconds)
  Do                                            'Wait until the PB compiler has done his job
    Sleep 200                                   'Sleep 200 ms (otherwise we steal useless power and the compiler needs longer)
    GetExitCodeProcess hProcessQuery,dwProcessExitCode
    If dwProcessExitCode<>%STILL_ACTIVE Then Exit Loop
  Loop Until timeGetTime()>dwTimeOut
  CloseHandle hProcessQuery
  SetCursor LoadCursor(%NULL,ByVal %IDC_ARROW)  'Normal mouse
  '
  'Now get the compiler output from the pipe:
  sCompilerOutput=String$(2048,0)  'Should be enough...
  ReadFile hInputPipe,ByVal StrPtr(sCompilerOutput),Len(sCompilerOutput),ByRef dwBytesGot,ByVal 0
  OemToCharBuff ByVal StrPtr(sCompilerOutput),ByVal StrPtr(sCompilerOutput),Len(sCompilerOutput)
  '  
  CloseHandle hOutputPipe  'Close pipe handle
  CloseHandle hInputPipe   'Close pipe handle
  '
  'Example compiler output in sCompilerOutput:
  'FreeBASIC Compiler - Version 0.12
  'Copyright (C) 2004-2005 Andre Victor T. Vicentini (av1ctor@yahoo.com.br)
  'compiling:    ddrawtest.bas -o ddrawtest.asm
  'ddrawtest.bas(27) : error 3: Expected End-of-Line, found: 'd'
  '
  dwBuffer=InStr(sCompilerOutput,szCurFileWithoutPath+"(")    'Get position of possible error string
  If dwBuffer Then  'Sorce code error
    dwBuffer=InStr(dwBuffer,sCompilerOutput,"(")+1            'Get position of line number
    dwLine=Val(Mid$(sCompilerOutput,dwBuffer))-1              'Get the line number
    dwStartPos=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwLine,0)  'Get start of expression position
    '
    SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwLine,0     'Open the sub containing this line if necessary
    SendScintillaMsg pSciWndData,%SCI_SETCURRENTPOS,dwStartPos,0   'Set end of selection
    SendScintillaMsg pSciWndData,%SCI_SETANCHOR,dwStartPos,0     'Set begin of selection
    SendScintillaMsg pSciWndData,%SCI_SCROLLCARET,0,0            'Scroll to the current caret position
    '
    dwRetVal=2
  End If
  If (dwMode=0) Or (dwProcessExitCode<>0) Then           'If Compiling only or error show the compiler result and exit
    MessageBox hWndMain,ByCopy sCompilerOutput,"Compiler result",0
    'hDlgCompilerOutput=CreateDialog(hInst,ByVal %IDD_COMPILEROUTPUT,hWndMain,CodePtr(CompilerOutputDlgFunc))
    'SetDlgItemText hDlgCompilerOutput,%IDC_COMPILEROUTPUT,ByCopy sCompilerOutput
    GoTo DoneCompile                                   'All is done, leave the function
  End If
  '
  'The following code we reach only if we have to run *and* compiling was successfull:
  If (ProjectSettings.dwTargetFileType=%TARGET_WIN32_GUI) Or (ProjectSettings.dwTargetFileType=%TARGET_WIN32_CONSOLE) Then
    If ProjectSettings.szTargetFilename="" Then 'No alternative target filename given
      szBuffer=Left$(szCurFile,InStr(-1,szCurFile,"."))+"exe"  'Filename is made from source filename and is an EXE
    Else
      szBuffer=ProjectSettings.szTargetFilename
    End If
    If WinExec(szBuffer,%SW_SHOW)<33 Then MessageBox hWndMain,"File not found:"+Chr$(13)+szBuffer,"",%MB_ICONSTOP
  End If
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneCompile:
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Function CompilerOutputDlgFunc(ByVal hDlg As Dword,ByVal Msg As Dword,ByVal wParam As Dword,ByVal lParam As Dword) As Long
  'Standard Dialog function for compiler output dialogbox (modal dialog)
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Select Case Msg
  Case %WM_INITDIALOG
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDOK,%IDCANCEL
      DestroyWindow hDlg
    End Select
    Function=1
  Case %WM_SIZE
    MoveWindow GetDlgItem(hDlg,%IDC_COMPILEROUTPUT),0,0,LoWrd(lParam),HiWrd(lParam),%TRUE  'Fit edit control into window
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function CompilePowerBasic(ByVal dwMode As Dword) As Dword
  'Compiles the current listing given by szCurFile.
  'dwMode: If 0 the funtion compiles only. If 1 the function compiles and if sucsessfull it starts the resulting program if EXE
  'Return values:
  '   0 if sucsessfull 
  '   1 if error staring compiler'
  '   2 Compiling error (error in sourcecode)
  'Shows the result in a MessageBox if not Run and successfull
  'Used global variables: szCurFile,szCurDir,szIncDir,szCompilerFile,hWndMain,pSciWndData
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  'Here is the PowerBasic compiler's command line syntax:
  'PBDLL.EXE [/Ipath] [/L] [/Q] FileName
  '/I  Compiler search path when looking for #INCLUDE and #RESOURCE files
  '/L  Generate a log file
  '/Q  ("quied") Don't display a message box when compiling is finished (use only with /L option)
  '/C  (>= PB 7.0) Specifies a filename that contains the complete command-line (allows command lines with up to 1024 bytes)
  'Note: For PowerBasic < 7.0 include directory and the filename short (8.3) names must be used and /C option isn't available.
  '      Anyway it's a good idea to use short names where possible to prevent crossing the 260 bytes path limitation
  'Example:
  'C:\PROGRA~1\POWERB~1\BIN\PBDLL.EXE C:\PROJEKTE\POWRBAS\MYTOOL.BAS /L /IC:\PROGRA~1\POWERB~1\WINAPI /Q
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static ProcessInfo As PROCESS_INFORMATION,StartInfo As STARTUPINFO,szCmdLine As Asciiz*%MAX_PATH*2
  Static szIncDirShort As Asciiz*160,szCompilerFileShort As Asciiz*160,szCurFileWithoutPath As Asciiz*160
  Static szLogFileName As Asciiz*%MAX_PATH
  Static dwLine As Dword,dwRow As Dword,dwStartPos As Dword,dwEndPos As Dword
  Static dwBuffer As Dword,szBuffer As Asciiz*%MAX_PATH,hProcessQuery As Dword,dwTimeOut As Dword,dwRetVal As Dword
  Static hLogFile As Dword,dwSizeLogFile As Dword,sLogFile As String,pszLogFile As Asciiz Ptr
  
  dwRetVal=0       'Set return value initial to "Success"
  hProcessQuery=0  'Invalidate Process handle used for query action

  If GetShortPathName(szIncDir,szIncDirShort,160)=0 Then
    MessageBox hWndMain,"No valid INCLUDE directory set (see menu "+$DQ+"Options"+$DQ+").","Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  If GetShortPathName(szCompilerFile,szCompilerFileShort,160)=0 Then
    MessageBox hWndMain,"No compiler set (see menu "+$DQ+"Options"+$DQ+").","Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  dwBuffer=InStr(-1,szCurFile,"\")+1 'Path information in?
  If dwBuffer>1 Then szCurFileWithoutPath=Mid$(szCurFile,dwBuffer)  'Remove path
  If szCurFileWithoutPath="" Then
    MessageBox hWndMain,"Illegal or no filename for the current listing."+Chr$(13)+szCurFile,"Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  If InStr(szCurFileWithoutPath," ") Then szCurFileWithoutPath=$DQ+szCurFileWithoutPath+$DQ 'Add quotes if there are spaces in filename
  '
  'Because we use the listing filename without path we must set the current directory. Above it's important to set
  'the current directory because the PB compiler writes the log file always into the current directory, not into
  'another one.
  SetCurrentDirectory Left$(szCurFile,InStr(-1,szCurFile,"\"))

  'szCmdLine=Extract$(szCompilerFileShort,$Nul)+" "+Extract$(szCurFileWithoutPath,$Nul)+" /I"+szIncDirShort
  szCmdLine=Extract$(szCompilerFileShort,$NUL)+" /L /Q "+szCurFileWithoutPath+" /I"+szIncDirShort
  'Poke$ VarPtr(ProcessInfo),String$(Len(ProcessInfo),0) 'Fill all fields with NULL
  If CreateProcess(ByVal 0,szCmdLine,ByVal 0,ByVal 0,%TRUE,%HIGH_PRIORITY_CLASS,ByVal 0,ByVal 0,StartInfo,ProcessInfo)=0 Then
    MessageBox hWndMain,"Command line:"+Chr$(13,13)+szCmdLine,"Error starting compiler:",%MB_ICONSTOP
    dwRetVal=1  'Return error
    GoTo DoneCompile
  End If
  
  'Wait until the compiler has done it's job:
  hProcessQuery=OpenProcess(%PROCESS_QUERY_INFORMATION,0,ProcessInfo.dwProcessId)
  SetCursor LoadCursor(%NULL,ByVal %IDC_WAIT)  'Wait mouse
  dwTimeOut=timeGetTime()+dwCompileTimeout*1000 'Timeout (dwCompileTimeout holds the user defined value in seconds)
  Do                                            'Wait until the PB compiler has done his job
    Sleep 200                                   'Sleep 200 ms (otherwise we steal useless power and the compiler needs longer)
    GetExitCodeProcess hProcessQuery,dwBuffer
    If dwBuffer<>%STILL_ACTIVE Then Exit Loop
  Loop Until timeGetTime()>dwTimeOut
  CloseHandle hProcessQuery
  SetCursor LoadCursor(%NULL,ByVal %IDC_ARROW)  'Normal mouse
  '
  'Read the created log file:
  'The log file gets the filename prefix of the listing, not the name given in the #COMPILE statement.
  'If this is for example TEST.BAS the log file is TEST.LOG
  'The LOG file will remain in the current (!) directory.
  szLogFileName=Left$(szCurFile,Len(szCurFile)-3)+"log" 'Name of the log file the compiler creates
  hLogFile=lopen(szLogFileName,%OF_READ)
  If hLogFile=%INVALID_HANDLE_VALUE Then  'Log file not found: Search in compiler directory
    MessageBox hWndMain,"Couldn't find the Log File."+Chr$(13)+szLogFileName,"Compiling error:",%MB_ICONSTOP
    dwRetVal=2
    GoTo DoneCompile                                   'All is done, leave the function
    '
    'szLogFileName=Left$(szCompilerFile,Instr(-1,szCompilerFile,"\"))+Mid$(szLogFileName,Instr(-1,szLogFileName,"\")+1)
    'hLogFile=lopen(szLogFileName,%OF_READ)
    'If hLogFile=%INVALID_HANDLE_VALUE Then  'Log file not found: Give up
    '  MessageBox hWndMain,"Couldn't find the Log File."+Chr$(13)+szLogFileName,"Compiling error:",%MB_ICONSTOP
    '  dwRetVal=2
    '  GoTo DoneCompile                                   'All is done, leave the function
    'End If
  End If
  dwSizeLogFile=llseek(hLogFile,0,%FILE_END)
  llseek hLogFile,0,%FILE_BEGIN
  pszLogFile=GlobalAlloc(%GMEM_FIXED,dwSizelogFile+1)
  @pszLogFile=""                                        'Prevents unexpected errors
  lread hLogFile,ByVal pszLogFile,dwSizeLogFile
  Poke pszLogFile+dwSizeLogFile,0                      'NULL termination
  lclose hLogFile
  DeleteFile szLogFileName                             'Delete possible log file
  '
  'Example Of Log file content:
  'PowerBASIC Compiler for Windows
  'PB/Win  Version 7.0  
  'Copyright (c) 1996-2002 PowerBasic Inc.
  'Carmel, California, USA
  'All Rights Reserved
  '
  'Error 504 in C:\PROJEKTE\PBEDITOR\TESTFILE.BAS(1:1):  Executable requires WinMain/PBMain function
  'Line 1: 'PowerBasic Editor based on scinpb.dll, an inofficial PowerBasic version of the great Scintilla Edit control.
  '
  'MessageBox hWndMain,ByVal pszLogFile,szLogFileName,0
  dwBuffer=InStr(@pszLogFile,Chr$(&H0D,&H0A)+"Error ")  'Get position of possible error message
  If dwBuffer Then  'Sorce code error
    dwBuffer=InStr(dwBuffer,@pszLogFile,"(")+1            'Get position of line number
    dwLine=Val(Mid$(@pszLogFile,dwBuffer))-1              'Get the line number
    dwBuffer=InStr(dwBuffer,@pszLogFile,":")+1            'Get position of row number
    dwRow=Val(Mid$(@pszLogFile,dwBuffer))-1               'Get the Row
    dwStartPos=SendScintillaMsg(pSciWndData,%SCI_POSITIONFROMLINE,dwLine,0)+dwRow  'Get start of expression position
    dwEndPos=SendScintillaMsg(pSciWndData,%SCI_WORDENDPOSITION,dwStartPos,0)       'Get end of expression position
    '
    SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwLine,0     'Open the sub containing this line if necessary
    SendScintillaMsg pSciWndData,%SCI_SETCURRENTPOS,dwEndPos,0   'Set end of selection
    SendScintillaMsg pSciWndData,%SCI_SETANCHOR,dwStartPos,0     'Set begin of selection
    SendScintillaMsg pSciWndData,%SCI_SCROLLCARET,0,0            'Scroll to the current caret position
    '
    dwRetVal=2
  End If
  If (dwMode=0 Or dwRetVal<>0) Then                         'If Compiling only or error show the compiler result and exit
    MessageBox hWndMain,ByVal pszLogFile,"Compiler result",0
    GoTo DoneCompile                                   'All is done, leave the function
  End If
  '
  'The following code we reach only if we have to run *and* compiling was successfull:
  '
  dwBuffer=GetCurExeFile(szBuffer)    'Is there a exe/dll filename specified in the listing? Get it if so.
  'If the statement isn't found in this part of the listing the function returns 0. szExeFile is set to ""
  'If the executable to create is a DLL the function returns 1. szExeFile contains the DLL filename
  'If the executable to create is a EXE the function returns 2. szExeFile contains the EXE filename
  Select Case dwBuffer
  Case 0   'No Compile statement found
    szBuffer=Left$(szCurFile,Len(szCurFile)-3)+"exe"  'Filename is made from source filename and is an EXE if PB 7.0
  Case 2  '#Compile or $Compile statement found, dwBuffer=2: Compile EXE
    If szBuffer="" Then
      szBuffer=Left$(szCurFile,Len(szCurFile)-3)+"exe"  'Get exe filename from source filename
    Else
      szBuffer=Left$(szCurFile,InStr(-1,szCurFile,"\"))+szBuffer
    End If
  'Case 1  '#Compile or $Compile statement found, dwBuffer=1: Compile DLL
    'Do nothing
  End Select
  If dwBuffer<>1 Then 'If no DLL
    If WinExec(szBuffer,%SW_SHOW)<33 Then MessageBox hWndMain,"File not found:"+Chr$(13)+szBuffer,"",%MB_ICONSTOP
  End If
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneCompile:
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Function SearchReplaceFunc(ByVal hDlg As Long,ByVal Msg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  'Standard Dialog function for the "Search/Replace" dialogbox (non-modal dialog), global handle: hDlgSearchReplace
  'Used global variables: hDlgSearchReplace,SrchWinRect,pSciWndData,hWndScintilla,sLastSearchKeyword,sLastReplaceKeyword
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static FindTxt As TextToFind,szBuffer As Asciiz*256,szBuffer2 As Asciiz*256,dwBuffer As Dword,RectTemp As Rect,dwCurLine As Dword
  Static hWndSearchBtn As Dword,hWndReplaceBtn As Dword,hWndReplaceAllBtn As Dword,hWndSearchEdit As Dword,hWndReplaceEdit As Dword
  Static dwSearchOptions As Dword,dwLenszBuffer As Dword,dwLenszBuffer2 As Dword,lCurPos As Long,dwEndOfText As Dword,dwTime As Dword
  'SCI_FINDTEXT(Int flags, TextToFind *ttf)
  'SCI_SEARCHANCHOR
  'SCI_SEARCHNEXT(Int searchFlags, Const char *Text)
  'SCI_SEARCHPREV(Int searchFlags, Const char *Text)
  Select Case Msg
  Case %WM_INITDIALOG
    If SrchWinRect.nRight=0 Then      'There is no valid windowe position in SrchWinRect
      GetWindowRect hDlg,SrchWinRect  'Rect.nLeft,Rect.nTop,Rect.nRight,Rect.nBottom (... AS LONG)
    Else                              'Restore the old position but get width and height always from original
      GetWindowRect hDlg,RectTemp     'Rect.nLeft,Rect.nTop,Rect.nRight,Rect.nBottom (... AS LONG)
      If SrchWinRect.nLeft<0 Then SrchWinRect.nLeft=0                                                                   'Ensure usefull position
      If SrchWinRect.nLeft>GetSystemMetrics(%SM_CXSCREEN)-100 Then SrchWinRect.nLeft=GetSystemMetrics(%SM_CXSCREEN)-100 'Ensure usefull position
      If SrchWinRect.nTop<0 Then SrchWinRect.nTop=0                                                                     'Ensure usefull position
      If SrchWinRect.nTop>GetSystemMetrics(%SM_CYSCREEN)-100 Then SrchWinRect.nTop=GetSystemMetrics(%SM_CYSCREEN)-100   'Ensure usefull position
      MoveWindow hDlg,SrchWinRect.nLeft,SrchWinRect.nTop,RectTemp.nRight-RectTemp.nLeft,RectTemp.nBottom-RectTemp.nTop,0
    End If
    '
    hWndSearchBtn=GetDlgItem(hDlg,%IDC_SEARCH)
    hWndReplaceBtn=GetDlgItem(hDlg,%IDC_REPLACE)
    hWndReplaceAllBtn=GetDlgItem(hDlg,%IDC_REPLACE_ALL)
    hWndSearchEdit=GetDlgItem(hDlg,%IDC_SEARCH_EDIT)
    hWndReplaceEdit=GetDlgItem(hDlg,%IDC_REPLACE_EDIT)
    '
    szBuffer=sLastSearchKeyword
    SendMessage hWndSearchEdit,%WM_SETTEXT,0,ByRef szBuffer   'Restore the last used Search keyword
    SendMessage hWndSearchEdit,%EM_LIMITTEXT,255,0            'Max 255 characters
    szBuffer=sLastReplaceKeyword
    SendMessage hWndReplaceEdit,%WM_SETTEXT,0,ByRef szBuffer  'Restore the last used Replace keyword
    SendMessage hWndReplaceEdit,%EM_LIMITTEXT,255,0           'Max 255 characters
    '
    EnableWindow hWndReplaceBtn,%FALSE                           'User must first do successfull search
    If SendMessage(hWndSearchEdit,%WM_GETTEXTLENGTH,0,0)=0 Then  'If no "Search" keyword given
      EnableWindow hWndSearchBtn,%FALSE
      EnableWindow hWndReplaceAllBtn,%FALSE
    End If
    '
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDC_SEARCH             'Button "Search"
      SendMessage hWndSearchEdit,%WM_GETTEXT,SizeOf(szBuffer),ByRef szBuffer
      FindTxt.chrg.cpMin=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)          'Start is end of current selection
      FindTxt.chrg.cpMax=SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)              'End of document
      FindTxt.lpstrText=VarPtr(szBuffer)                                               'The search pattern (NULL terminated)
      'FindTxt.chrgText.cpMin=                                                         'Returned as position of matching text
      'FindTxt.chrgText.cpMax=                                                         'Returned as position of matching text
      dwSearchOptions=0
      If IsDlgButtonChecked(hDlg,%IDC_SRCH_WORD) Then dwSearchOptions=%SCFIND_WHOLEWORD                     'CheckBox "Whole word"
      If IsDlgButtonChecked(hDlg,%IDC_SRCH_CASE) Then dwSearchOptions=dwSearchOptions Or %SCFIND_MATCHCASE  'CheckBox "Match case"
      If SendScintillaMsg(pSciWndData,%SCI_FINDTEXT,dwSearchOptions,ByRef FindTxt)=-1 Then
        MessageBox hDlg,"No (more) matches found",$APP_NAME_SHORT,%MB_ICONSTOP
      Else
        dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,FindTxt.chrgText.cpMin,0)
        SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwCurLine,0                    'Open the sub containing this line if necessary
        SendScintillaMsg pSciWndData,%SCI_SETCURRENTPOS,FindTxt.chrgText.cpMax,0       'Set end of selection
        SendScintillaMsg pSciWndData,%SCI_SETANCHOR,FindTxt.chrgText.cpMin,0           'Set begin of selection
        SendScintillaMsg pSciWndData,%SCI_SCROLLCARET,0,0                              'Scroll to the current caret position
        EnableWindow hWndReplaceBtn,%TRUE
      End If
    Case %IDC_REPLACE              'Button "Replace"
      FindTxt.chrgText.cpMax=SendScintillaMsg(pSciWndData,%SCI_GETCURRENTPOS,0,0)       'Get end of selection
      FindTxt.chrgText.cpMin=SendScintillaMsg(pSciWndData,%SCI_GETANCHOR,0,0)           'Get begin of selection
      If FindTxt.chrgText.cpMax=FindTxt.chrgText.cpMin Then
        MessageBox hDlg,"There is no selected text to replace."+Chr$(13)+_
                        "Use "+$DQ+"Search"+$DQ+" first.",$APP_NAME_SHORT,%MB_ICONSTOP
        EnableWindow hWndReplaceBtn,%FALSE
      Else
        SendMessage hWndReplaceEdit,%WM_GETTEXT,SizeOf(szBuffer),ByRef szBuffer
        SendScintillaMsg pSciWndData,%SCI_REPLACESEL,0,ByRef szBuffer
        PostMessage hDlg,%WM_COMMAND,%IDC_SEARCH,0      'Search next
      End If
    Case %IDC_REPLACE_ALL          'Button "Replace all"
      'Note: We can replace using SCI_REPLACESEL or SCI_REPLACETARGET. Both options need about the same time (very slow),
      '      SCI_REPLACETARGET is very minor faster.
      If MessageBox(hDlg,"Depending on the number of replacements this operation"+$CR+_
                         "unfortunately may need a bit time."+$CR+$CR+_
                         "Really replace all from current position to end of listing?","Replace all",%MB_ICONQUESTION Or %MB_YESNO)=%IDYES Then
        SendMessage hWndSearchEdit,%WM_GETTEXT,SizeOf(szBuffer),ByRef szBuffer
        SendMessage hWndReplaceEdit,%WM_GETTEXT,SizeOf(szBuffer2),ByRef szBuffer2
        '
'        FindTxt.chrg.cpMin=SendScintillaMsg(pSciWndData,%SCI_GETANCHOR,0,0)              'Start is begin of current selection
'        FindTxt.chrg.cpMax=SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)              'End of document
'        FindTxt.lpstrText=VarPtr(szBuffer)                                               'The search pattern (NULL terminated)
'        'FindTxt.chrgText.cpMin=                                                         'Returned as position of matching text
'        'FindTxt.chrgText.cpMax=                                                         'Returned as position of matching text
'        dwSearchOptions=0
'        If IsDlgButtonChecked(hDlg,%IDC_SRCH_WORD) Then dwSearchOptions=%SCFIND_WHOLEWORD                     'CheckBox "Whole word"
'        If IsDlgButtonChecked(hDlg,%IDC_SRCH_CASE) Then dwSearchOptions=dwSearchOptions Or %SCFIND_MATCHCASE  'CheckBox "Match case"
'        dwBuffer=0 'Counter
'        dwTime=timeGetTime()
'        While SendScintillaMsg(pSciWndData,%SCI_FINDTEXT,dwSearchOptions,ByRef FindTxt)>-1
'          SendScintillaMsg pSciWndData,%SCI_SETCURRENTPOS,FindTxt.chrgText.cpMax,0       'Set end of selection
'          SendScintillaMsg pSciWndData,%SCI_SETANCHOR,FindTxt.chrgText.cpMin,0           'Set begin of selection
'          SendScintillaMsg pSciWndData,%SCI_EMPTYUNDOBUFFER,0,0
'          SendScintillaMsg pSciWndData,%SCI_REPLACESEL,0,ByRef szBuffer2                 'Replace selection
'          Incr dwBuffer  'Counter
'        Wend
'        dwTime=timeGetTime()-dwTime
'        SendScintillaMsg pSciWndData,%SCI_SETCURRENTPOS,FindTxt.chrgText.cpMin+Len(szBuffer2),0  'Select last replaced word (end of selection)
'        SendScintillaMsg pSciWndData,%SCI_SETANCHOR,FindTxt.chrgText.cpMin,0                     'Set begin of selection
'        dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,FindTxt.chrgText.cpMin,0)
'        SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwCurLine,0                    'Open the sub containing this line if necessary
'        SendScintillaMsg pSciWndData,%SCI_SCROLLCARET,0,0                              'Scroll to the current caret position
'        'MessageBox hDlg,LTrim$(Str$(dwBuffer))+" occurrences replaced.",$APP_NAME_SHORT,%MB_ICONINFORMATION
'        MessageBox hDlg,LTrim$(Str$(dwBuffer))+" occurrences replaced."+$Cr+"Needed time:"+Str$(dwTime)+" Milliseconds",$APP_NAME_SHORT,%MB_ICONINFORMATION

        dwSearchOptions=0
        If IsDlgButtonChecked(hDlg,%IDC_SRCH_WORD) Then dwSearchOptions=%SCFIND_WHOLEWORD                     'CheckBox "Whole word"
        If IsDlgButtonChecked(hDlg,%IDC_SRCH_CASE) Then dwSearchOptions=dwSearchOptions Or %SCFIND_MATCHCASE  'CheckBox "Match case"
        SendScintillaMsg pSciWndData,%SCI_SETSEARCHFLAGS,dwSearchOptions,0
        SendScintillaMsg pSciWndData,%SCI_SETTARGETSTART,SendScintillaMsg(pSciWndData,%SCI_GETANCHOR,0,0),0 'Start is begin of current selection
        dwEndOfText=SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)                                        'End of document position
        SendScintillaMsg pSciWndData,%SCI_SETTARGETEND,dwEndOfText,0                                        'End is end of document
        dwBuffer=0 'Counter
        dwLenszBuffer=Len(szBuffer)
        dwLenszBuffer2=Len(szBuffer2)
        lCurPos=0
        dwTime=timeGetTime()
        Do
          If (dwBuffer And &B00000001) Then 'Show we are still working (replacing needs some time!)
            SetCursor LoadCursor(%NULL,ByVal %IDC_APPSTARTING)
          Else
            SetCursor LoadCursor(%NULL,ByVal %IDC_WAIT)
          End If
          lCurPos=SendScintillaMsg(pSciWndData,%SCI_SEARCHINTARGET,dwLenszBuffer,ByRef szBuffer) 'Search and set new target
          If lCurPos=-1 Then Exit Loop
          SendScintillaMsg pSciWndData,%SCI_REPLACETARGET,dwLenszBuffer2,ByRef szBuffer2         'Replace text in target
          'SendScintillaMsg pSciWndData,%SCI_SETTARGETSTART,SendScintillaMsg(pSciWndData,%SCI_GETTARGETEND,0,0),0   'New target start
          SendScintillaMsg pSciWndData,%SCI_SETTARGETSTART,lCurPos+dwLenszBuffer2,0   'New target start
          SendScintillaMsg pSciWndData,%SCI_SETTARGETEND,dwEndOfText,0                           'Target end is end of document
          Incr dwBuffer  'Counter
        Loop
        dwTime=timeGetTime()-dwTime
        SetCursor LoadCursor(%NULL,ByVal %IDC_ARROW)
        lCurPos=SendScintillaMsg(pSciWndData,%SCI_GETTARGETSTART,0,0)
        SendScintillaMsg pSciWndData,%SCI_SETCURRENTPOS,lCurPos,0                      'Select last replaced word (end of selection)
        SendScintillaMsg pSciWndData,%SCI_SETANCHOR,lCurPos-dwLenszBuffer2,0           'Set begin of selection
        dwCurLine=SendScintillaMsg(pSciWndData,%SCI_LINEFROMPOSITION,lCurPos,0)
        SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwCurLine,0                    'Open the sub containing this line if necessary
        SendScintillaMsg pSciWndData,%SCI_SCROLLCARET,0,0                              'Scroll to the current caret position
        'MessageBox hDlg,LTrim$(Str$(dwBuffer))+" occurrences replaced.",$APP_NAME_SHORT,%MB_ICONINFORMATION
        MessageBox hDlg,LTrim$(Str$(dwBuffer))+" occurrences replaced."+$CR+"Needed time:"+Str$(dwTime)+" Milliseconds",$APP_NAME_SHORT,%MB_ICONINFORMATION
      End If
    Case %IDC_SEARCH_EDIT             'Edit control with the search keyword
      If HiWrd(wParam)=%EN_CHANGE Then
        EnableWindow hWndReplaceBtn,%FALSE   'When the user changes the search keyword he must first do a successfull Search before Replace
        If SendMessage(hWndSearchEdit,%WM_GETTEXTLENGTH,0,0)=0 Then 'If no "Search" keyword 
          EnableWindow hWndSearchBtn,%FALSE
          EnableWindow hWndReplaceAllBtn,%FALSE
        Else
          EnableWindow hWndSearchBtn,%TRUE
          EnableWindow hWndReplaceAllBtn,%TRUE
        End If
      End If
    Case %IDC_DONE                 'Button "Done"
      SendMessage hWndSearchEdit,%WM_GETTEXT,SizeOf(szBuffer),ByRef szBuffer
      sLastSearchKeyword=szBuffer              'Store the last used Search keyword in global variable
      SendMessage hWndReplaceEdit,%WM_GETTEXT,SizeOf(szBuffer),ByRef szBuffer
      sLastReplaceKeyword=szBuffer              'Store the last used Replace keyword in global variable
      GetWindowRect hDlg,SrchWinRect           'Get position+size of the dialog box for later calls
      DestroyWindow hDlg
      hDlgSearchReplace=%INVALID_HANDLE_VALUE  'Invalidate dialog handle (for IsDialogMessage call)
      SetFocus hWndScintilla
    End Select
    Function=1                                            '
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function GoToFunc(ByVal hDlg As Long,ByVal Msg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  'Standard Dialog function for the "GoTo" dialogbox (non-modal dialog), global handle: hDlgGoTo
  'Used global variables: hDlgGoTo,GoToWinRect,pSciWndData,hWndScintilla
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static szBuffer As Asciiz*32,dwBuffer As Dword,RectTemp As Rect,dwCurLine As Dword
  '
  Select Case Msg
  Case %WM_INITDIALOG
    If GoToWinRect.nRight=0 Then      'There is no valid windowe position in GoToWinRect
      GetWindowRect hDlg,GoToWinRect  'Rect.nLeft,Rect.nTop,Rect.nRight,Rect.nBottom (... AS LONG)
    Else                              'Restore the old position but get width and height always from original
      GetWindowRect hDlg,RectTemp     'Rect.nLeft,Rect.nTop,Rect.nRight,Rect.nBottom (... AS LONG)
      If GoToWinRect.nLeft<0 Then GoToWinRect.nLeft=0                                                                 'Ensure usefull position
      If GoToWinRect.nLeft>GetSystemMetrics(%SM_CXSCREEN)-50 Then GoToWinRect.nLeft=GetSystemMetrics(%SM_CXSCREEN)-50 'Ensure usefull position
      If GoToWinRect.nTop<0 Then GoToWinRect.nTop=0                                                                   'Ensure usefull position
      If GoToWinRect.nTop>GetSystemMetrics(%SM_CYSCREEN)-50 Then SrchWinRect.nTop=GetSystemMetrics(%SM_CYSCREEN)-50   'Ensure usefull position
      MoveWindow hDlg,GoToWinRect.nLeft,GoToWinRect.nTop,RectTemp.nRight-RectTemp.nLeft,RectTemp.nBottom-RectTemp.nTop,0
    End If
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDC_GOTO_EDIT
      GetDlgItemText hDlg,%IDC_GOTO_EDIT,szBuffer,SizeOf(szBuffer)
      dwCurLine=Val(szBuffer)-1
      SendScintillaMsg pSciWndData,%SCI_ENSUREVISIBLE,dwCurLine,0    'Open the sub containing this line if necessary
      SendScintillaMsg pSciWndData,%SCI_GOTOLINE,dwCurLine,0
    Case %IDCANCEL
      GetWindowRect hDlg,GoToWinRect        'Get position+size of the dialog box for later calls
      DestroyWindow hDlg
      hDlgGoTo=%INVALID_HANDLE_VALUE      'Invalidate dialog handle (for IsDialogMessage call)
      SetFocus hWndScintilla
    End Select
    Function=1                                            '
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function GeneralSettingsDlgFunc(ByVal hDlg As Long,ByVal Msg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  'Standard Dialog function for the "General settings" dialogbox
  'Used global variables: hInst,szEditorDir,szTemplateDir,szIncDir,szCompilerFile,szPbResToolFile,szResEditFile,szApiHelpFile,szBasicHelpFile
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static szBuffer As Asciiz*%MAX_PATH,szDirNameTemp As Asciiz*%MAX_PATH,Ofn As OPENFILENAME,sFilter As String
  Static hWndQuickhelp As Dword,hWndLastQuickHelp As Dword,dwTemp As Dword ',hFontSmall
  '
  Select Case Msg
  Case %WM_INITDIALOG
    'hFontSmall=CreateFont(16,0,0,0,%FW_NORMAL,%FALSE,%FALSE,%FALSE,%ANSI_CHARSET,%OUT_DEFAULT_PRECIS,%CLIP_DEFAULT_PRECIS,%PROOF_QUALITY,%FIXED_PITCH Or %FF_SWISS,ByVal 0)
    hWndQuickhelp=GetDlgItem(hDlg,%IDC_GS_QUICKHELP)
    '
    SetDlgItemText hDlg,%IDC_GS_TEMPDIR,szTemplateDir
    SetDlgItemText hDlg,%IDC_GS_INCLUDEDIR,szIncDir
    SetDlgItemText hDlg,%IDC_GS_COMPILER,szCompilerFile
    SetDlgItemText hDlg,%IDC_GS_RESCONVERTER,szPbResToolFile
    SetDlgItemText hDlg,%IDC_GS_RESEDITOR,szResEditFile
    SetDlgItemText hDlg,%IDC_GS_APIHELP,szApiHelpFile
    SetDlgItemText hDlg,%IDC_GS_BASICHELP,szBasicHelpFile
    SetDlgItemText hDlg,%IDC_GS_BASICKEYLIST,szBasicKeywordFile
    SetDlgItemText hDlg,%IDC_GS_APIKEYLIST,szApiKeywordFile
    SetDlgItemText hDlg,%IDC_GS_CONSTANTKEYLIST,szConstantKeywordFile
    SendDlgItemMessage hDlg,%IDC_GS_BASICKEYLIST,%EM_SETMODIFY,%FALSE,0      'Checked when leaving dialog with "OK"
    SendDlgItemMessage hDlg,%IDC_GS_APIKEYLIST,%EM_SETMODIFY,%FALSE,0        'Checked when leaving dialog with "OK"
    SendDlgItemMessage hDlg,%IDC_GS_CONSTANTKEYLIST,%EM_SETMODIFY,%FALSE,0   'Checked when leaving dialog with "OK"
    '
    Select Case dwCompilerType
    Case %CMPTYPE_POWERBASIC
      CheckDlgButton hDlg,%IDC_GS_COMPILER_PB,%BST_CHECKED
      EnableWindow GetDlgItem(hDlg,%IDC_GS_CONSTANTKEYLIST),%FALSE     'Disable edit control "Constant keyword list"
      EnableWindow GetDlgItem(hDlg,%IDC_GS_CONSTANTKEYLIST_S),%FALSE   'Disable file selection for "Constant keyword list"
    Case Else  '%CMPTYPE_FREEBASIC,%CMPTYPE_UNKNOWN
      CheckDlgButton hDlg,%IDC_GS_COMPILER_FB,%BST_CHECKED
      EnableWindow GetDlgItem(hDlg,%IDC_GS_RESCONVERTER),%FALSE     'Disable edit control "PB resource converter"
      EnableWindow GetDlgItem(hDlg,%IDC_GS_RESCONVERTER_S),%FALSE   'Disable file selection for "PB resource converter"
    End Select
    '
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDOK
      For dwTemp=%CMPTYPE_FREEBASIC To %CMPTYPE_UNKNOWN             '%CMPTYPE_FREEBASIC=0, %CMPTYPE_UNKNOWN has the first unused ID
        If IsDlgButtonChecked(hDlg,%IDC_GS_COMPILER_FB+dwTemp) Then '%CMPTYPE_FREEBASIC has the lowest control ID
          dwCompilerType=dwTemp
          Exit For
        End If
      Next dwTemp
      '
      GetDlgItemText hDlg,%IDC_GS_BASICKEYLIST,szBuffer,SizeOf(szBuffer)
      Select Case dwCompilerType
      Case %CMPTYPE_FREEBASIC
        If InStr(UCase$(szBuffer),"POWERBASIC") Then 'Typical user error
          If MessageBox(hDlg,"You have selected the FreeBasic compiler but the"+$CR+"Basic keyword filename contains the string "+_
                             $DQ+"PowerBasic"+$DQ+"."+$CR+"Really continue?","Possible error",_
                             %MB_ICONQUESTION Or %MB_YESNO Or %MB_DEFBUTTON2)=%IDNO Then GoTo GeneralSettingsDlgFunc_CancelOk
        End If
      Case Else '%CMPTYPE_POWERBASIC             '%CMPTYPE_FREEBASIC=0, %CMPTYPE_UNKNOWN has the first unused ID
        If InStr(UCase$(szBuffer),"FREEBASIC") Then 'Typical user error
          If MessageBox(hDlg,"You have selected the PowerBasic compiler but the"+$CR+"Basic keyword filename contains the string "+_
                             $DQ+"FreeBasic"+$DQ+"."+$CR+"Really continue?","Possible error",_
                             %MB_ICONQUESTION Or %MB_YESNO Or %MB_DEFBUTTON2)=%IDNO Then GoTo GeneralSettingsDlgFunc_CancelOk
        End If
      End Select
      '      
      GetDlgItemText hDlg,%IDC_GS_TEMPDIR,szTemplateDir,SizeOf(szTemplateDir)
      GetDlgItemText hDlg,%IDC_GS_INCLUDEDIR,szIncDir,SizeOf(szIncDir)
      GetDlgItemText hDlg,%IDC_GS_COMPILER,szCompilerFile,SizeOf(szCompilerFile)
      GetDlgItemText hDlg,%IDC_GS_RESCONVERTER,szPbResToolFile,SizeOf(szPbResToolFile)
      GetDlgItemText hDlg,%IDC_GS_RESEDITOR,szResEditFile,SizeOf(szResEditFile)
      GetDlgItemText hDlg,%IDC_GS_APIHELP,szApiHelpFile,SizeOf(szApiHelpFile)
      GetDlgItemText hDlg,%IDC_GS_BASICHELP,szBasicHelpFile,SizeOf(szBasicHelpFile)
      GetDlgItemText hDlg,%IDC_GS_BASICKEYLIST,szBasicKeywordFile,SizeOf(szBasicKeywordFile)
      GetDlgItemText hDlg,%IDC_GS_APIKEYLIST,szApiKeywordFile,SizeOf(szApiKeywordFile)
      GetDlgItemText hDlg,%IDC_GS_CONSTANTKEYLIST,szConstantKeywordFile,SizeOf(szConstantKeywordFile)
      '
      If WritePrivateProfileString($PATH,$INCLUDEDIR,szIncDir,szIniFile)<>0 Then
        WritePrivateProfileString $PATH,$TEMPLATEDIR,szTemplateDir,szIniFile
        WritePrivateProfileString $PATH,$BASICHELPFILE,szBasicHelpFile,szIniFile
        WritePrivateProfileString $PATH,$APIHELPFILE,szApiHelpFile,szIniFile
        WritePrivateProfileString $PATH,$COMPILERFILE,szCompilerFile,szIniFile
        If dwCompilerType=%CMPTYPE_POWERBASIC Then WritePrivateProfileString $PATH,$PBRESTOOLFILE,szPbResToolFile,szIniFile
        WritePrivateProfileString $PATH,$RESEDITFILE,szResEditFile,szIniFile
        WritePrivateProfileString $PATH,$BASICKEYWORDFILE,szBasicKeywordFile,szIniFile
        WritePrivateProfileString $PATH,$APIKEYWORDFILE,szApiKeywordFile,szIniFile
        WritePrivateProfileString $PATH,$CONSTANTKEYWORDFILE,szConstantKeywordFile,szIniFile
        szBuffer=LTrim$(Str$(dwCompilerType))
        WritePrivateProfileString $OTHERSETTINGS,$COMPILERTYPE,szBuffer,szIniFile
      End If
      '
      LoadKeywordList hDlg  'Reload the keyword list files
      'If SendDlgItemMessage(hDlg,%IDC_GS_BASICKEYLIST,%EM_GETMODIFY,0,0) Then      'Basic keyword list file changed
      'ElseIf SendDlgItemMessage(hDlg,%IDC_GS_APIKEYLIST,%EM_GETMODIFY,0,0) Then    'API keyword list file changed
      '  LoadKeywordList hDlg
      'ElseIf If (dwCompilerType<>%CMPTYPE_POWERBASIC) And (SendDlgItemMessage(hDlg,%IDC_GS_CONSTANTKEYLIST,%EM_GETMODIFY,0,0)) Then  'Constant keyword list file changed
      '  LoadKeywordList hDlg
      'End If
      '
      EndDialog hDlg,0
      GeneralSettingsDlgFunc_CancelOk:
    Case %IDCANCEL
      EndDialog hDlg,0
    Case %IDC_GS_TEMPDIR_S,%IDC_GS_INCLUDEDIR_S             'Directory selection buttons
      If LoWrd(wparam)= %IDC_GS_TEMPDIR_S Then
        GetDlgItemText hDlg,%IDC_GS_TEMPDIR,szDirNameTemp,SizeOf(szDirNameTemp)
      Else      '%IDC_GS_INCLUDEDIR_S
        GetDlgItemText hDlg,%IDC_GS_INCLUDEDIR,szDirNameTemp,SizeOf(szDirNameTemp)
      End If
      If szDirNameTemp="" Then szDirNameTemp=szEditorDir
      szBuffer            = ""            'Ofn.lpstrFile=VarPtr(szBuffer)
      sFilter             = ""+$NUL+$NUL
      Poke$ VarPtr(Ofn),String$(Len(Ofn),0) 'Fill OPENFILENAME structure initial with 0
      Ofn.lStructSize   = Len(Ofn)
      Ofn.hwndOwner     = hDlg
      Ofn.hInstance     = hInst
      Ofn.nFilterIndex  = 1
      Ofn.nMaxFile      = %MAX_PATH
      'Ofn.FlagsEx      = %OFN_EX_NOPLACESBAR   'Win2000: Don't show icons for favorits, desktop and so on
      Ofn.lpstrFilter     = StrPtr(sFilter)
      Ofn.lpstrFile       = VarPtr(szBuffer)
      Ofn.lpstrInitialDir = VarPtr(szDirNameTemp)
      Ofn.lpTemplateName  = %IDD_DIRSELECT        'Own dialog template based on the "old" commdlg file selection dialog
      Ofn.Flags           = %OFN_ENABLETEMPLATE Or %OFN_PATHMUSTEXIST Or %OFN_NOVALIDATE Or %OFN_NOTESTFILECREATE
      If GetSaveFileName(OFN)<>0 Then
        GetCurrentDirectory SizeOf(szDirNameTemp),szDirNameTemp            'Retrieved path is uppercase under Windows 9x/ME (why???)
        GetLongPathName szDirNameTemp,szDirNameTemp,SizeOf(szDirNameTemp)  'Get mixed case path name
        If LoWrd(wparam)= %IDC_GS_TEMPDIR_S Then
          SetDlgItemText hDlg,%IDC_GS_TEMPDIR,szDirNameTemp+"\"
        Else      '%IDC_GS_INCLUDEDIR_S
          SetDlgItemText hDlg,%IDC_GS_INCLUDEDIR,szDirNameTemp+"\"
        End If
      End If
    Case %IDC_GS_COMPILER_S            'Compiler selection button
      SelectFileToControl hDlg,%IDC_GS_COMPILER,"*.exe"+$NUL+"*.EXE"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_RESCONVERTER_S        'PowerBasic Resource converter file selection button
      SelectFileToControl hDlg,%IDC_GS_RESCONVERTER,"*.exe"+$NUL+"*.EXE"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_RESEDITOR_S           'Resource editor file selection button
      SelectFileToControl hDlg,%IDC_GS_RESEDITOR,"*.exe"+$NUL+"*.EXE"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_APIHELP_S             'API help file file selection button
      SelectFileToControl hDlg,%IDC_GS_APIHELP,"*.hlp;*.col;*.chm"+$NUL+"*.HLP;*.COL;*.CHM"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_BASICHELP_S           'Basic help file file selection button
      SelectFileToControl hDlg,%IDC_GS_BASICHELP,"*.hlp;*.col;*.chm"+$NUL+"*.HLP;*.COL;*.CHM"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_BASICKEYLIST_S        'Basic keyword list file selection button
      SelectFileToControl hDlg,%IDC_GS_BASICKEYLIST,"*.txt"+$NUL+"*.TXT"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_APIKEYLIST_S          'API keyword list file selection button
      SelectFileToControl hDlg,%IDC_GS_APIKEYLIST,"*.txt"+$NUL+"*.TXT"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_CONSTANTKEYLIST_S     'Constant keyword list file selection button
      SelectFileToControl hDlg,%IDC_GS_CONSTANTKEYLIST,"*.txt"+$NUL+"*.TXT"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,szEditorDir
    Case %IDC_GS_COMPILER_FB,%IDC_GS_COMPILER_PB                       'RadioButtons Compiler type
      If IsDlgButtonChecked(hDlg,%IDC_GS_COMPILER_PB) Then             'PowerBasic compiler selected
        EnableWindow GetDlgItem(hDlg,%IDC_GS_RESCONVERTER),%TRUE       'Enable edit control "PB resource converter"
        EnableWindow GetDlgItem(hDlg,%IDC_GS_RESCONVERTER_S),%TRUE     'Enable file selection for "PB resource converter"
        EnableWindow GetDlgItem(hDlg,%IDC_GS_CONSTANTKEYLIST),%FALSE   'Disable edit control "Constant keyword list"
        EnableWindow GetDlgItem(hDlg,%IDC_GS_CONSTANTKEYLIST_S),%FALSE 'Disable file selection for "Constant keyword list"
      Else
        EnableWindow GetDlgItem(hDlg,%IDC_GS_RESCONVERTER),%FALSE       'Disable edit control "PB resource converter"
        EnableWindow GetDlgItem(hDlg,%IDC_GS_RESCONVERTER_S),%FALSE     'Disable file selection for "PB resource converter"
        EnableWindow GetDlgItem(hDlg,%IDC_GS_CONSTANTKEYLIST),%TRUE     'Enable edit control "Constant keyword list"
        EnableWindow GetDlgItem(hDlg,%IDC_GS_CONSTANTKEYLIST_S),%TRUE   'Enable file selection for "Constant keyword list"
      End If
    End Select
    Function=1
  Case %WM_SETCURSOR                'The QuickHelp function
    If wParam<>hWndLastQuickHelp Then
      hWndLastQuickHelp=wParam
      Select Case GetDlgCtrlID(wParam)
      Case %IDOK                     'The "OK" button
        SetWindowText hWndQuickhelp,"Make changes permanent and leave dialog."
      Case %IDCANCEL                 'The "Cancel" button
        SetWindowText hWndQuickhelp,"Reject changes and leave dialog."
      Case %IDC_GS_TEMPDIR           'Template directory
        SetWindowText hWndQuickhelp,"Directory opened when clicking menu item File-->New-->By template file..."
      Case %IDC_GS_INCLUDEDIR        'Include directory
        SetWindowText hWndQuickhelp,"Directory for the include files. For PowerBasic by default "+$DQ+"WINAPI"+$DQ+" and for FreeBasic "+$DQ+"INC"+$DQ+"."
      Case %IDC_GS_COMPILER          'PB Compiler (pbdll.exe/pbdll16.exe/pbwin.exe)
        SetWindowText hWndQuickhelp,"Path+Filename of the FreeBasic compiler (fbc.exe) or the PowerBasic compiler (pbdll.exe/pbdll16.exe/pbwin.exe/pbcc.exe, by default in "+$DQ+"BIN"+$DQ+" directory)."
      Case %IDC_GS_RESCONVERTER      'PB Resource converter (pbres.exe)
        SetWindowText hWndQuickhelp,"Needed for PowerBasic Win/CC only: Resource converter which converts the *.pbr resource file into a standard Windows *.res resource file (pbres.exe). By default found in "+$DQ+"BIN"+$DQ+" directory."
      Case %IDC_GS_RESEDITOR         'Resource editor (must be able to load *.res files, for example Borland Resource Workshop) with...
        SetWindowText hWndQuickhelp,"Resource editor opened with menu item Tools-->Edit resources. In PowerBasic the resource filename is taken from #RESORCE statement. More see in editor's help."
      Case %IDC_GS_APIHELP           'API help file
        SetWindowText hWndQuickhelp,"API help file for context sensitive help and menu entry Help-->API help. Can be either be a WinHelp (*.hlp) or HTML help (*.col/*.chm) file."+_
                                    " For other files (for example *.exe) ShellExecute() is called with or wihout a keyword as command line parameter."
      Case %IDC_GS_BASICHELP         'Basic help file
        SetWindowText hWndQuickhelp,"Basic help file for context sensitive help and menu entry Help-->Basic help. Can be either be a WinHelp (*.hlp) or HTML help (*.col/*.chm) file."+_
                                    " For other files (for example *.exe) ShellExecute() is called with or wihout a keyword as command line parameter."
      Case %IDC_GS_BASICKEYLIST      'Basic keyword list file
        SetWindowText hWndQuickhelp,"Text file containing a space-separated list of Basic keywords for syntax coloring, auto case correction and context-sensitive help. If not existing the editor creates the file with default content."
      Case %IDC_GS_APIKEYLIST        'API keyword list file
        SetWindowText hWndQuickhelp,"Text file containing a space-separated list of Windows API keywords for syntax coloring, auto case correction and context-sensitive help. If not existing the editor creates the file with default content."
      Case %IDC_GS_CONSTANTKEYLIST   'Constant keyword list file
        SetWindowText hWndQuickhelp,"Not needed for PowerBasic: Text file containing a space-separated list of constant keywords for syntax coloring, auto case correction and context-sensitive help. If not existing the editor creates the "+_
                                    "file with default content."
      'Case %IDC_GS_QUICKHELP         'Quick help STATIC control
      '  SetWindowtext hWndQuickhelp,""
      Case %IDC_GS_TEMPDIR_S,%IDC_GS_INCLUDEDIR_S,%IDC_GS_COMPILER_S,%IDC_GS_RESCONVERTER_S,%IDC_GS_RESEDITOR_S,%IDC_GS_APIHELP_S,_
           %IDC_GS_BASICHELP_S,%IDC_GS_BASICKEYLIST_S,%IDC_GS_APIKEYLIST_S,%IDC_GS_CONSTANTKEYLIST_S
        SetWindowText hWndQuickhelp,"Select the file/directory by file selection box."
      Case Else
        SetWindowText hWndQuickhelp,""
      End Select
    End If
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function SelectFileToControl(ByVal hDlg As Dword,ByVal idControl As Dword,ByVal sFilter As String,ByVal sDefaultDir As String) As Dword
  'Helper for GeneralSettingsDlgFunc() and ProjectSettingsDlgFunc(). Gets the filename from a control and opens a file
  'selection box with it. After successfull selection the selected filename is set back to the control.
  'Used global variables: hInst
  '
  Static szFileName As Asciiz*%MAX_PATH,szDirName As Asciiz*%MAX_PATH,Ofn As OPENFILENAME
  '
  GetDlgItemText hDlg,idControl,szFileName,SizeOf(szFileName)    'Ofn.lpstrFile=VarPtr(szBuffer)
  If szFileName="" Then
    szDirName=sDefaultDir
  Else
    szDirName=Left$(szFileName,InStr(-1,szFileName,"\"))
  End If

  'Preset the OFN type members which are always the same in the "Path settings" dialog:
  Poke$ VarPtr(Ofn),String$(Len(Ofn),0) 'Fill OPENFILENAME structure initial with 0
  Ofn.lStructSize   = Len(Ofn)
  Ofn.hwndOwner     = hDlg
  Ofn.hInstance     = hInst
  Ofn.nFilterIndex  = 1
  Ofn.nMaxFile      = %MAX_PATH
  'Ofn.FlagsEx      = %OFN_EX_NOPLACESBAR   'Win2000: Don't show icons for favorits, desktop and so on
  Ofn.lpstrFilter     = StrPtr(sFilter)
  Ofn.lpstrFile       = VarPtr(szFileName)
  Ofn.lpstrInitialDir = VarPtr(szDirName)
  Ofn.lpTemplateName  = %NULL
  Ofn.Flags           = %OFN_HIDEREADONLY
  If GetOpenFileName(OFN)<>0 Then
    SetDlgItemText hDlg,idControl,szFileName
    Function=1
  Else
    Function=0
  End If
End Function
'*************************************************************************************************************************************
Function FontDlgFunc(ByVal hDlg As Long,ByVal Msg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  'Standard Dialog function for the "Font & Colors" dialogbox (modal dialog)
  'Used global variables: dwUserFontSize,szUserFont, Type UserColor
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static idCtl As Dword,hWndCtl As Dword,pDrawItem As DRAWITEMSTRUCT Ptr
  Static szBuffer As Asciiz*64,dwCurColor As Dword
  Static i As Long,j As Long,k As Long
  Static hWndFontSize As Dword,hWndFontName As Dword,hFont As Dword,hOldFont As Dword
  Dim AvailableColors(0 To 11) As Static Long 'As many elemets as colors the user can select
  Dim szTextLabels(0 To 8) As Static Asciiz*32   'receives the labels for the text color comboboxes
  Static dwMaxAvailableColors As Dword
  Dim UserColorLocal(0 To ArrayAttr(szTextLabels(),4)-1) As Static Dword 'As many elements as array szTextLabels()
  Static hOldPen As Dword,hOldBrush As Dword,hPen As Dword,hBrush As Dword
  '
  Select Case Msg
  Case %WM_INITDIALOG
    'Set the available font sizes into the combobox:
    hWndFontSize=GetDlgItem(hDlg,%IDC_FS_FONTSIZE)
    For i=4 To 18
      szBuffer=LTrim$(Str$(i))
      SendMessage hWndFontSize,%CB_ADDSTRING,0,ByRef szBuffer
    Next i
    szBuffer=LTrim$(Str$(dwUserFontSize))  'The current font size is stored in the global variable dwUserFontSize
    If SendMessage(hWndFontSize,%CB_SELECTSTRING,-1,ByRef szBuffer)=%CB_ERR Then  'Select the combobox entry with the current font size
      szBuffer="9"  'If error select "9" as default size
      SendMessage hWndFontSize,%CB_SELECTSTRING,-1,ByRef szBuffer
    End If
    '
    'Now fill the "Font name" combobox with the available fonts and select the font the user had set before:
    hWndFontName=GetDlgItem(hDlg,%IDC_FS_FONTNAME)
    EnumFontFamilies GetDC(%NULL),ByVal %NULL,ByVal CodePtr(EnumFontProc),ByVal hWndFontName 'The enumeration callback sets the fonts into the combobox
    If SendMessage(hWndFontName,%CB_SELECTSTRING,-1,ByRef szUserFont)=%CB_ERR Then  'Select the combobox entry with the current font name
      szBuffer="Courier New"
      If SendMessage(hWndFontName,%CB_SELECTSTRING,-1,ByRef szBuffer)=%CB_ERR Then 'Try to select "Courier New" alternatively
        SendMessage hWndFontName,%CB_SETCURSEL,0,0                                'Af also impossible select the first font in the list
      End If
    End If
    '
    'Define the available colors (usefull colors only, to many colors are not very helpfull!):
    AvailableColors(0)=RGB(0,0,0)       'black
    AvailableColors(1)=RGB(128,128,128) 'dark gray
    AvailableColors(2)=RGB(128,64,0)    'brown
    AvailableColors(3)=RGB(128,0,0)     'dark red
    AvailableColors(4)=RGB(255,0,0)     'red
    AvailableColors(5)=RGB(255,128,64)  'orange
    AvailableColors(6)=RGB(255,0,128)   'light violett
    AvailableColors(7)=RGB(128,0,128)   'violett
    AvailableColors(8)=RGB(64,64,255)   'light blue
    AvailableColors(9)=RGB(0,0,255)     'blue
    AvailableColors(10)=RGB(0,0,128)    'dark blue
    AvailableColors(11)=RGB(0,128,0)    'dark green

    dwMaxAvailableColors=ArrayAttr(AvailableColors(),4)-1 'Get index of highest field
    '
    'The used labels for the text colors:
    szTextLabels(0)="&API keywords"   '%IDC_FS_APIKEYWORDS  =201
    szTextLabels(1)="&Basic keywords" '%IDC_FS_BASICKEYWORDS=202
    szTextLabels(2)="&Strings"        '%IDC_FS_STRINGS      =203
    szTextLabels(3)="&Numbers"        '%IDC_FS_NUMBERS      =204
    szTextLabels(4)="O&perators"      '%IDC_FS_OPERATORS    =205
    szTextLabels(5)="Co&mments"       '%IDC_FS_COMMENTS     =206
    szTextLabels(6)="Cons&tants"      '%IDC_FS_CONSTANTS    =207
    szTextLabels(7)="Ass&embler"      '%IDC_FS_ASM          =208
    szTextLabels(8)="&Default"        '%IDC_FS_DEFAULT      =209
    UserColorLocal(0)=UserColor(%SCE_B_APIKEYWORD)   '%IDC_FS_APIKEYWORDS   =201
    UserColorLocal(1)=UserColor(%SCE_B_BASICKEYWORD) '%IDC_FS_BASICKEYWORDS =202
    UserColorLocal(2)=UserColor(%SCE_B_STRING)       '%IDC_FS_STRINGS       =203
    UserColorLocal(3)=UserColor(%SCE_B_NUMBER)       '%IDC_FS_NUMBERS       =204
    UserColorLocal(4)=UserColor(%SCE_B_OPERATOR)     '%IDC_FS_OPERATORS     =205
    UserColorLocal(5)=UserColor(%SCE_B_COMMENT)      '%IDC_FS_COMMENTS      =206
    UserColorLocal(6)=UserColor(%SCE_B_CONSTANT)     '%IDC_FS_CONSTANTS     =207
    UserColorLocal(7)=UserColor(%SCE_B_ASM)          '%IDC_FS_ASM           =208
    UserColorLocal(8)=UserColor(%SCE_B_DEFAULT)      '%IDC_FS_DEFAULT       =209
    '
    'And now fill the text color comboboxes with it's label and color:
    For j=0 To ArrayAttr(szTextLabels(),4)-1  'All DIMed szTextLabels() elements
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_APIKEYWORDS+j)
      idCtl=0
      For i=0 To dwMaxAvailableColors
        k=SendMessage(hWndCtl,%CB_ADDSTRING,0,ByRef szTextLabels(j))
        SendMessage hWndCtl,%CB_SETITEMDATA,k,AvailableColors(i)
        If AvailableColors(i)=UserColorLocal(j) Then idCtl=k             'If current color is used color then store item id for selection
      Next i
      SendMessage hWndCtl,%CB_SETCURSEL,idCtl,0
    Next j
    '
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDOK
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_APIKEYWORDS)
      UserColor(%SCE_B_APIKEYWORD)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_BASICKEYWORDS)
      UserColor(%SCE_B_BASICKEYWORD)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_STRINGS)
      UserColor(%SCE_B_STRING)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_NUMBERS)
      UserColor(%SCE_B_NUMBER)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_OPERATORS)
      UserColor(%SCE_B_OPERATOR)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_COMMENTS)
      UserColor(%SCE_B_COMMENT)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_CONSTANTS)
      UserColor(%SCE_B_CONSTANT)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_ASM)
      UserColor(%SCE_B_ASM)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      hWndCtl=GetDlgItem(hDlg,%IDC_FS_DEFAULT)
      UserColor(%SCE_B_DEFAULT)=SendMessage(hWndCtl,%CB_GETITEMDATA,SendMessage(hWndCtl,%CB_GETCURSEL,0,0),0)
      '
      'Store the font size into the global variable holding the user-selected font-size
      SendMessage hWndFontSize,%CB_GETLBTEXT,SendMessage(hWndFontSize,%CB_GETCURSEL,0,0),ByRef szBuffer
      dwUserFontSize=Val(szBuffer)
      If dwUserFontSize=0 Then dwUserFontSize=9  'Error preventer
      'Get the current selected font name and store it into the responsible global variable:
      SendMessage hWndFontName,%CB_GETLBTEXT,SendMessage(hWndFontName,%CB_GETCURSEL,0,0),ByRef szUserFont
      '
      If WritePrivateProfileString($WINDOWS,$FONTNAME,szUserFont,szIniFile)<>0 Then
        szBuffer=LTrim$(Str$(dwUserFontSize))
        WritePrivateProfileString $WINDOWS,$FONTSIZE,szBuffer,szIniFile
        UserColor(%SCE_B_IDENTIFIER)=UserColor(%SCE_B_DEFAULT) 'Internaly same color as %SCE_B_DEFAULT
        WritePrivateProfileStruct $WINDOWS,$SYNTAXCOLORS,ByRef UserColor(0),ArrayAttr(UserColor(),4)*ArrayAttr(UserColor(),5),szIniFile
      End If
      '
      EndDialog hDlg,1  'Return value 1 signals dialog box was closed with "OK"
    Case %IDCANCEL
      EndDialog hDlg,0  'Return value 0 signals dialog box was closed with "Cancel"
    End Select
    Function=1
  Case %WM_DRAWITEM 'Draw the text color combo boxes
    pDrawItem=lParam
    SetBkMode @pDrawItem.hDC,%TRANSPARENT
    dwCurColor=SendMessage(@pDrawItem.hwndItem,%CB_GETITEMDATA,@pDrawItem.itemID,0)
    SetTextColor @pDrawItem.hDC,dwCurColor
    If (@pDrawItem.itemState And %ODS_FOCUS) Then  'The control has the focus
      hOldPen=SelectObject(@pDrawItem.hDC,CreatePen(%PS_SOLID,3,dwCurColor))
    Else
      hOldPen=SelectObject(@pDrawItem.hDC,CreatePen(%PS_SOLID,1,dwCurColor))
    End If
    SendMessage @pDrawItem.hwndItem,%CB_GETLBTEXT,@pDrawItem.itemID,ByRef szBuffer
    Rectangle @pDrawItem.hDC,@pDrawItem.RcItem.nLeft,@pDrawItem.RcItem.nTop,@pDrawItem.RcItem.nRight,@pDrawItem.RcItem.nBottom
    DrawText @pDrawItem.hDC,szBuffer,-1,ByVal VarPtr(@pDrawItem.RcItem),%DT_CENTER Or %DT_SINGLELINE Or %DT_VCENTER
    DeleteObject(SelectObject(@pDrawItem.hDC,hOldPen))
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function ProjectSettingsDlgFunc(ByVal hDlg As Long,ByVal Msg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  'Standard Dialog function for the "Project settings" dialogbox
  'Used global variables: hInst, szCurFile, type ProjectSettings,
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static szBuffer As Asciiz*%MAX_PATH,hWndQuickhelp As Dword,hWndLastQuickHelp As Dword,hWndTargetFileType As Dword
  Static sProjectDir As String
  '
  Select Case Msg
  Case %WM_INITDIALOG
    hWndQuickhelp=GetDlgItem(hDlg,%IDC_GS_QUICKHELP)
    hWndTargetFileType=GetDlgItem(hDlg,%IDC_PRJ_TARGETFILETYPE)
    '
    If szCurFile="" Then
      SetWindowText hDlg,"Project settings for current file"
    Else
      SetWindowText hDlg,"Project settings for "+Mid$(szCurFile,InStr(-1,szCurFile,"\")+1)
    End If
    '
    szBuffer="Win32 console application (*.exe)"
    SendMessage hWndTargetFileType,%CB_INSERTSTRING,%TARGET_WIN32_CONSOLE,ByRef szBuffer
    szBuffer="Win32 GUI application (*.exe)"
    SendMessage hWndTargetFileType,%CB_INSERTSTRING,%TARGET_WIN32_GUI,ByRef szBuffer
    szBuffer="Win32 dynamic library (*.dll)"
    SendMessage hWndTargetFileType,%CB_INSERTSTRING,%TARGET_WIN32_DLL,ByRef szBuffer
    szBuffer="Win32 static library (*.lib)"
    SendMessage hWndTargetFileType,%CB_INSERTSTRING,%TARGET_WIN32_LIB,ByRef szBuffer
    szBuffer="Win32 object file (*.obj)"
    SendMessage hWndTargetFileType,%CB_INSERTSTRING,%TARGET_WIN32_OBJ,ByRef szBuffer
    If SendMessage(hWndTargetFileType,%CB_SETCURSEL,ProjectSettings.dwTargetFileType,0)=%CB_ERR Then
      SendMessage hWndTargetFileType,%CB_SETCURSEL,0,0
    End If
    '
    SetDlgItemText hDlg,%IDC_PRJ_RESFILENAME,ProjectSettings.szResFile
    SetDlgItemText hDlg,%IDC_PRJ_TARGETFILENAME,ProjectSettings.szTargetFilename
    '
    sProjectDir=Left$(szCurFile,InStr(-1,szCurFile,"\"))  'Used as default directory for file selection dialog
    '
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDOK
      ProjectSettings.dwTargetFileType=SendMessage(hWndTargetFileType,%CB_GETCURSEL,0,0)
      GetDlgItemText hDlg,%IDC_PRJ_RESFILENAME,ProjectSettings.szResFile,SizeOf(ProjectSettings.szResFile)
      GetDlgItemText hDlg,%IDC_PRJ_TARGETFILENAME,ProjectSettings.szTargetFilename,SizeOf(ProjectSettings.szResFile)
      '
      'SendMessage hWndScintilla,%EM_SETMODIFY,%True,0   'Doesn't work and no replacement available!
      '
      EndDialog hDlg,0
    Case %IDCANCEL
      EndDialog hDlg,0
    Case %IDC_PRJ_TARGETFILETYPE
      If HiWrd(wParam)=%CBN_SELCHANGE Then 'Change QuickHelp text if selection changed
        hWndLastQuickHelp=0
        PostMessage hDlg,%WM_SETCURSOR,hWndTargetFileType,0
      End If
    Case %IDC_PRJ_RESFILENAME_S        'PushButton "Select resource file"
      SelectFileToControl hDlg,%IDC_PRJ_RESFILENAME,"*.res;*.rc"+$NUL+"*.RES;*.RC"+$NUL+"*.*"+$NUL+"*.*"+$NUL+$NUL,sProjectDir
    Case %IDC_PRJ_TARGETFILENAME_S     'PushButton "Select target filename"
      SelectFileToControl hDlg,%IDC_PRJ_TARGETFILENAME,"*.*"+$NUL+"*.*"+$NUL+$NUL,sProjectDir
    End Select
  Case %WM_SETCURSOR                'The QuickHelp function
    If wParam<>hWndLastQuickHelp Then
      hWndLastQuickHelp=wParam
      Select Case GetDlgCtrlID(wParam)
      Case %IDOK                     'The "OK" button
        SetWindowText hWndQuickhelp,"Use current settings and leave dialog."
      Case %IDCANCEL                 'The "Cancel" button
        SetWindowText hWndQuickhelp,"Reject changes and leave dialog."
      Case %IDC_PRJ_TARGETFILETYPE
        szBuffer="File type to compile: "
        Select Case SendMessage(hWndTargetFileType,%CB_GETCURSEL,0,0)
        Case %TARGET_WIN32_CONSOLE
          szBuffer=szBuffer+"Win32 textmode application (*.exe)"
        Case %TARGET_WIN32_GUI
          szBuffer=szBuffer+"Win32 standard application (*.exe)"
        Case %TARGET_WIN32_DLL
          szBuffer=szBuffer+"Win32 dynamic link library (*.dll)"
        Case %TARGET_WIN32_LIB
          szBuffer=szBuffer+"Win32 static library (*.lib)"
        Case %TARGET_WIN32_OBJ
          szBuffer=szBuffer+"Win32 object file (*.obj)"
        End Select
        SetWindowText hWndQuickhelp,szBuffer
      Case %IDC_PRJ_RESFILENAME
        SetWindowText hWndQuickhelp,"Filename of the Resource file containing dialog templates, menues, "+_
                                    "version info and so on. Open+edit with menu Tools-->Edit resources."
      Case %IDC_PRJ_TARGETFILENAME
        SetWindowText hWndQuickhelp,"Alternative target filename with or without path. Leave empty to generate the "+_
                                    "filename from the currently loaded file."
      Case Else
        SetWindowText hWndQuickhelp,""
      End Select
    End If
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function CodeFormatterDlgFunc(ByVal hDlg As Long,ByVal Msg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  'Standard Dialog function for the "Code formatter" dialogbox
  'Used global variables: hInst,...
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static hWndQuickhelp As Dword,hWndLastQuickHelp As Dword,i As Long,j As Long,k As Long
  '
  Select Case Msg
  Case %WM_INITDIALOG
    hWndQuickhelp=GetDlgItem(hDlg,%IDC_CF_QUICKHELP)
    '
    Function=1          'Set focus to default control
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDOK
      'First we must enshure to let Scintilly style the entire listing. Without probably only the current visible text
      'might be styled. Because we use the Scintilla style bits to find the keywords we whould process a part of the listing
      'only if not the entire text is styled.
      SendScintillaMsg pSciWndData,%SCI_GOTOLINE,SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0),0 'Go to end of listing
      SetTimer hDlg,1,55,ByVal 0     'Do the rest after WM_TIMER
    Case %IDCANCEL
      EndDialog hDlg,0
    Case %IDC_CF_BAS_KEYWORDS         'Checkbox "Change Basic keywords"
    Case %IDC_CF_API_KEYWORDS         'Checkbox "Change API keywords"
    Case %IDC_CF_CONST_KEYWORDS       'Checkbox "Change constants"
    End Select
  Case %WM_SETCURSOR                  'The QuickHelp function
    If wParam<>hWndLastQuickHelp Then
      hWndLastQuickHelp=wParam
      Select Case GetDlgCtrlID(wParam)
      Case %IDOK                     'The "OK" button
        SetWindowText hWndQuickhelp,"Execute the selected changes and leave dialog."
      Case %IDCANCEL                 'The "Cancel" button
        SetWindowText hWndQuickhelp,"Do nothing and leave dialog."
      Case %IDC_CF_BAS_KEYWORDS      'Checkbox "Change Basic keywords disabled"
        SetWindowText hWndQuickhelp,"Change Basic keywords to mixed case as specified in Basic keyword list file."
      Case %IDC_CF_API_KEYWORDS      'Checkbox "Change API keywords disabled"
        SetWindowText hWndQuickhelp,"Change API keywords to mixed case as specified in API keyword list file."
      Case %IDC_CF_CONST_KEYWORDS    'Checkbox "Change constants disabled"
        SetWindowText hWndQuickhelp,"Change numeric+string constants to uppercase. For FreeBasic a constant keyword "+_
                                    "list file is needed. For PowerBasic no list file necessary."
      Case Else
        SetWindowText hWndQuickhelp,"The code formatter can correct the case of keywords. Correction is done for "+_
                                    "the entire listing."
      End Select
    End If
  Case %WM_TIMER '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    'WM_TIMER with Id 1 is sent to style the entire listing. This gives Scintilla time to style the listing. More see WM_COMMAN=IDOK
    KillTimer hDlg,1
    If IsDlgButtonChecked(hDlg,%IDC_CF_BAS_KEYWORDS) Then i=1 Else i=0        'Checkbox "Change Basic keywords"
    If IsDlgButtonChecked(hDlg,%IDC_CF_API_KEYWORDS) Then j=1 Else j=0        'Checkbox "Change API keywords"
    If IsDlgButtonChecked(hDlg,%IDC_CF_CONST_KEYWORDS) Then k=2 Else k=0      'Checkbox "Change constants"
    If i=0 And j=0 And k=0 Then
      MessageBox hDlg,"Set at least one checkbox, otherwise there's nothing to do...","",%MB_ICONSTOP
    Else
      CodeFormatterChangeCase i,j,k 'Parameters: lDoBas,lDoApi,lDoConst [0: NoChange,1: MixedCase,2: UpperCase,3: LowerCase]
      EndDialog hDlg,0
    End If
  Case Else
    Function=%FALSE
  End Select
End Function
'*************************************************************************************************************************************
Function CodeFormatterChangeCase(ByVal lDoBas As Long,ByVal lDoApi As Long,ByVal lDoConst As Long) As Dword
  'Reformats the keyword cases in the entire loaded file, called from CodeFormatterDlgFunc()
  'lDoBas:     0: Don't change Basic keywords,    1: MixedCase [Reserved: , 2: UpperCase, 3: LowerCase]
  'lDoApi:     0: Don't change API keywords,      1: MixedCase [Reserved: , 2: UpperCase, 3: LowerCase]
  'lDoConst:   0: Don't change constant keywords, 2: UpperCase [Reserved: , 1: MixedCase, 3: LowerCase]
  '
  'The "strategy" is to get the entire text styled by Scintilla to find the keywords by it's styling attributes. This is done
  'with the message SCI_GETSTYLEDTEXT. After correction of the entire listing we empty the control and set the text back using
  'the message SCI_ADDSTYLEDTEXT. This is much faster then correcting step by step inside the control.
  'Watch: It's important that Scintilla has just styled the entire listing. This can be done by jumping to the very last line
  'using SCI_GOTOLINE and giving Scintilla enough time for styling after.
  '
  'Small known "problem": The very last keyword in the listing isn't processed if no other characters follow such as Cr+Rt or space.
  '
  'Return values: 0 if Sucsessfull [Reserverd: 1 if error]
  '
  'Global variables: pSciWndData,sBasicKeyWords,sApiKeyWords,sBasicKeyWordsLCase,sApiKeyWordsLCase
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Static dwRetVal As Dword,dwFileSize As Dword,TxtRange As TEXTRANGE,pInByte As Byte Ptr,pOutByte As Byte Ptr,i As Long
  Static pCurChar As Byte Ptr,pCurStyle As Byte Ptr,bCurStyle As Byte,bLastStyle As Byte
  Static pStartOfKeyword As Byte Ptr,pEndOfKeyword As Byte Ptr,sCurKeyword As String  ',sBuffer As String,i As Long
  Static lLenKeyword As Long,dwPosInList As Dword,sCurKeywordCorrectCase As String
  'Static bRed As Byte,bGreen As Byte,bBlue As Byte
  '  
  dwRetVal=0    'Set function return value initially to "successsfull"
  '
  SetCursor LoadCursor(%NULL,ByVal %IDC_APPSTARTING)   'For very long listings we need a bit time, show hourglass mouse
  '
  'Get the styled text from Scintilla control:
  dwFileSize=(SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)*2)+2   '1 cell needs 2 bytes plus 2 terminating NULL characters
  TxtRange.chrg.cpMin=0
  TxtRange.chrg.cpMax=SendScintillaMsg(pSciWndData,%SCI_GETLENGTH,0,0)
  TxtRange.lpstrText=GlobalAlloc(%GMEM_FIXED,dwFileSize)
  SendScintillaMsg pSciWndData,%SCI_GETSTYLEDTEXT,0,ByRef TxtRange
  '
  'Each character is given as a Cell of 2 bytes. The lower byte contains the character and the upper byte the style information.
  'The lowest 5 bits of the Style byte contains the text attributes (values 0...31).
  sCurKeyword=""
  For pCurChar=TxtRange.lpstrText To TxtRange.lpstrText+dwFileSize-4 Step 2
    pCurStyle=pCurChar+1
    bLastStyle=bCurStyle
    bCurStyle=(@pCurStyle And &B00011111) 'Only the lower 5 bits are interesting for us (text attributes)
    If bCurStyle=bLastStyle Then                'The style doesn't change
      If bCurStyle=%SCE_B_CONSTANT Then
        If lDoConst=2 Then '2: Change to uppercase
          If (@pCurChar>&H60) And (@pCurChar<&H7B) Then @pCurChar=@pCurChar And &B11011111  'a...z lowercase ==> A...Z uppercase
        End If
      Else
        Select Case bLastStyle
        Case %SCE_B_BASICKEYWORD,%SCE_B_APIKEYWORD
          sCurKeyword=sCurKeyword+Chr$(@pCurChar)  'Add the current character to the current keyword
          pEndOfKeyword=pCurChar                   'Get the current position as (present) end of current keyword
        End Select
      End If
    Else                                         'The style has been changed: Process the last keyword
      lLenKeyword=Len(sCurKeyword)
      Select Case bLastStyle
      Case %SCE_B_BASICKEYWORD
        If (lDoBas) And (lLenKeyword) Then
          dwPosInList=InStr(sBasicKeyWordsLCase," "+LCase$(sCurKeyword)+" ")
          If dwPosInList Then sCurKeywordCorrectCase=Mid$(sBasicKeyWords,dwPosInList,lLenKeyword)
        End If
      Case %SCE_B_APIKEYWORD
        If (lDoApi) And (lLenKeyword) Then
          dwPosInList=InStr(sApiKeyWordsLCase," "+LCase$(sCurKeyword)+" ")
          If dwPosInList Then sCurKeywordCorrectCase=Mid$(sApiKeyWords,dwPosInList,lLenKeyword)
        End If
      Case Else
        dwPosInList=0
      End Select
      If (dwPosInList) And (sCurKeyword<>sCurKeywordCorrectCase) Then
        pInByte=StrPtr(sCurKeywordCorrectCase)
        For pOutByte=pStartOfKeyword To pEndOfKeyword Step 2 'Copy the correct sized keyword
          @pOutByte=@pInByte
          Incr pInByte
        Next pOutByte
      End If                                   'If lLenKeyword Then -----------------------------------------------------------
      sCurKeyword=Chr$(@pCurChar)              'Get the current character as first character of the current keyword
      pStartOfKeyword=pCurChar                 'Get the current position as start of current keyword
    End If
  Next pCurChar
  '
  SendScintillaMsg pSciWndData,%SCI_CLEARALL,0,0
  SendScintillaMsg pSciWndData,%SCI_ADDSTYLEDTEXT,dwFileSize-2,TxtRange.lpstrText  'Size: Minus the 2 terminating NULL characters
  SendScintillaMsg pSciWndData,%SCI_GOTOLINE,SendScintillaMsg(pSciWndData,%SCI_GETLINECOUNT,0,0),0
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  DoneSaveFile:
  SetCursor LoadCursor(%NULL,ByVal %IDC_ARROW)   'Show standard mouse
  '
  If TxtRange.lpstrText<>0 Then GlobalFree TxtRange.lpstrText
  
  Function=dwRetVal
End Function
'*************************************************************************************************************************************
Function EnumFontProc(Elf As ENUMLOGFONT,Ntm As NEWTEXTMETRIC,ByVal dwFontType As Dword,ByVal hWndCombobox As Dword) As Dword
  'Enumeration callback function for EnumFontFamilies(), called in dialog box function FontDlgFunc().
  'The Callback chooses fonts (only) which are possibly usefull for the editor and adds them to the FontName
  'Combobox given by the handle hWndCombobox.
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  'Elf.elfFullName
  Static FontFamily As Byte

  FontFamily = Elf.elfLogFont.lfPitchAndFamily And &B11110000  
  If FontFamily<>%FF_SWISS And FontFamily<>%FF_MODERN And FontFamily<>%FF_ROMAN Then GoTo DoneEnumFontProc

  If Elf.elfLogFont.lfCharSet<>%ANSI_CHARSET Then GoTo DoneEnumFontProc

  SendMessage hWndCombobox,%CB_ADDSTRING,0,ByRef Elf.elfLogFont.lfFaceName

  DoneEnumFontProc:
  Function=1
  'If (dwFontType And %RASTER_FONTTYPE) Then
  'ElseIf (dwFontType And %TRUETYPE_FONTTYPE) Then
  '  'ANSI_CHARSET
  'Else 
  'End If
End Function
'*************************************************************************************************************************************
Function EditorHelpDlgProc(ByVal hDlg As Dword,ByVal wMsg As Dword,ByVal wParam As Dword,ByVal lParam As Dword) As Long
  'Standard Dialog function for the "Editor's help" dialogbox (non-modal dialog). Global window handle: hDlgEditorHelp
  'Hint: This dialog displays RTF files loaded from user-defined resources.
  Static hwndEdit As Dword, hResFind As Dword,EditStreamInfo As EDITSTREAM,hwndList As Dword
  'Global variable: ResInfo
  '
  Select Case wMsg
  Case %WM_INITDIALOG
    hwndEdit=GetDlgItem(hDlg,%IDC_HLP_HLPTEXT)
    hwndList=GetDlgItem(hDlg,%IDC_HLP_PAGESELBOX)
    SendMessage hwndList,%WM_SETFONT,GetStockObject(%ANSI_VAR_FONT),0   'Set smaller font for the list box
    '
    'Now set the index into the listbox. The order must be exactly as in the RTF file:
    'The RTF file uses the character ÿ as a page separator.
    szBuffer="Content"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    szBuffer="First steps"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    szBuffer="The different options"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    szBuffer="Use with more then one compiler"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    szBuffer="Some backgrounds"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    szBuffer="Resource editors"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    szBuffer="FAQ"
    SendMessage hwndList,%LB_ADDSTRING,0,VarPtr(szBuffer)
    SendMessage hwndList,%LB_SETCURSEL,0,0  'Select the first entry of the listbox (content)
    PostMessage hDlg,%WM_COMMAND,MakLng(%IDC_HLP_PAGESELBOX,%LBN_SELCHANGE),hwndList  'Results opening the currently selected page
    '
    MoveWindow hDlg,GetSystemMetrics(%SM_CXSCREEN)\3,0,GetSystemMetrics(%SM_CXSCREEN)*2\3,GetSystemMetrics(%SM_CYSCREEN),%FALSE  'Results WM_SIZE
    Function=%TRUE 'TRUE: Direct the system to set the keyboard focus to the default control
 Case %WM_SIZE
    MoveWindow hwndList,0,0,150,HiWrd(lParam),%TRUE                  'Fit List control into window
    MoveWindow hwndEdit,150,0,LoWrd(lParam)-150,HiWrd(lParam),%TRUE  'Fit Richedit control into window
    Function=%FALSE
  Case %WM_COMMAND
    Select Case LoWrd(wParam)
    Case %IDCANCEL   'ESC key
      DestroyWindow hDlg
    'Case %IDC_HLP_HLPTEXT          'Richedit control for the help text
    'Case %IDC_HLP_SEARCHPAGE       'Search page Edit control
    Case %IDC_HLP_PAGESELBOX       'Listbox
      If HiWrd(wParam)=%LBN_SELCHANGE Then
        'Load the RTF help file from user defined resource and set resource information into type ResInfo
        hResFind=FindResource(hInst,ByVal %IDRES_EDITORHELP,ByVal %IDREST_EDITORHELP)
        If hResFind=0 Then
          SetWindowText hwndEdit,"Help page not found"
        Else
          'The global type ResInfo contains the RTF file information for the stream function:
          ResInfo.hRes=LoadResource(hInst,hResFind)     'Resource handle of the user-defined resource containing the RTF file
          ResInfo.lStartAdr=LockResource(ResInfo.hRes)  'Start address of the RTF file in memory (incremented by the stream function)
          ResInfo.lEndAdr=ResInfo.lStartAdr+SizeofResource(hInst,hResFind) 'End address of the RTF file in memory
          ResInfo.lTargetPageId=SendMessage(lParam,%LB_GETCURSEL,0,0)+1    'ID of the RTF page to show (>=1 because 0 is the RTF header)
          ResInfo.lCurPageId=0                      'Current RTF page ID, incremented by the streaming function, must be 0 initially
          EditStreamInfo.dwCookie=0
          EditStreamInfo.pfnCallback=CodePtr(StreamInEditorHelp)
          EditStreamInfo.dwError=0
          SendMessage hwndEdit,%EM_STREAMIN,%SF_RTF Or %SFF_PLAINRTF,VarPtr(EditStreamInfo)
        End If
      End If
      Function=1                                            '
    End Select
'  Case %WM_SYSKEYDOWN
'    If wParam=%VK_ESCAPE Then DestroyWindow hDlg  'ESC key
'  Case %WM_SETFOCUS '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'    SetFocus hwndEdit
'    Function=0
  Case Else '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Function=%FALSE
  End Select
End Function
'****************************************************************************************************************************************************************
Function StreamInEditorHelp(ByVal dwCookie As Dword,ByVal lOutBuffer As Long,ByVal lBytesToRead As Long,ByRef lBytesRead As Dword) Export As Long
  'Helper callback for EditorHelpDlgProc() read in RTF-Stream from resource. The RTF file is separated into several pages which
  'are displayed separately. The page numbers start with 1. Page number 0 is illegal because this is needed for the RTF header.
  'Each help pages starts with ASCII character 127 () as a page separator. This chrarcter is very usefull because it's nearly
  'unused under normal circumstances. Compared with the "normal page break" it has two advantages: First it is a single character
  'which is extremely simple to handle with streaming and results faster processing then the rtf code "\page ". Second both
  'editors based on richedit.dll and Wordpad are not able to create "real" page breaks but create smaller files then Word for
  'Windows or other text processors. By the way: Ascii-127 isn't a special encoded character in RTF files. Characters >127 *can*
  'be stored as single bytes in RTF files under MS Windows but are mostly encoded as rtf token ("\'FF " for example).
  '
  'ResInfo.hRes            Resource handle of the user-defined resource containing the RTF file
  'ResInfo.lStartAdr       Start address of the RTF file in memory, incremented by the stream function
  'ResInfo.lEndAdr         End address of the RTF file in memory
  'ResInfo.lTargetPageId   ID of the RTF page to show. Must be >=1 because 0 is the RTF header
  'ResInfo.lCurPageId      Current RTF page ID, incremented by the streaming function, must be 0 initially
  '
  Static pInByte As Byte Ptr,pOutByte As Byte Ptr
  '
  'Now stream in the RTF header only (this is for us page 0). The start of the text is marked by the page separator character Ascii-127
  lBytesRead=0
  pOutByte=lOutBuffer
  For pInByte=ResInfo.lStartAdr To ResInfo.lEndAdr
    If @pInByte=127 Then              'Page start character Ascii-127: Update the ID of the current RTF page
      Incr ResInfo.lCurPageId
    Else
      Select Case ResInfo.lCurPageId
      Case 0,ResInfo.lTargetPageId    'We are at page 0 (the RTF header) or inside the target page which is to display
        @pOutByte=@pInByte            'Copy the current byte
        Incr pOutByte
        Incr lBytesRead
      Case >ResInfo.lTargetPageId     'We are above the target page
        @pOutByte=Asc("}")            'Terminates the RTF file if done often enough
        Incr lBytesRead
        Exit For
      End Select
    End If
    Incr ResInfo.lStartAdr
    If lBytesRead>=lBytesToRead Then Exit For
  Next pInByte
  '
  Function = 0
End Function
'*************************************************************************************************************************************
Sub AboutApp(ByVal hWndParent As Dword)
  'Shows MessageBox with program information.
  'Loads the version information from VERSIONINFO resource of application exe.
  'Hint: With some older Windows versions the resource functions doesn't work if EXE loaded from network (Microsoft bug).
  '      But don't ask me which versions - I can't remember it ;-)
  'Global variables: szEditorFile
  '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Dim hRes As Long, lpRes As Long
  Dim lenVersion As Long, sVersion As String
  Dim lpInfoBuffer As Dword,LenInfoBuffer As Long
  Dim sFileVersion As String
  Dim sFileComment As String
  Dim sOriginalFilename As String
  Dim sCompanyName As String
  Dim sLegalCopyright As String
  Dim szBuffer As Asciiz*1024

  lenVersion=GetFileVersionInfoSize(szEditorFile,ByVal 0)
  sVersion=String$(lenVersion,0)
  GetFileVersionInfo szEditorFile,0,lenVersion,ByVal StrPtr(sVersion)   'Load version information (watch: strings are Unicode!!!)
  '
  VerQueryValue ByVal StrPtr(sVersion),"\StringFileInfo\040904E4\Comments",lpInfoBuffer,LenInfoBuffer 'Get string version info
  sFileComment=Peek$(lpInfoBuffer,LenInfoBuffer-1)                                                    'Without NULL termination
  '
  VerQueryValue ByVal StrPtr(sVersion),"\StringFileInfo\040904E4\OriginalFilename",lpInfoBuffer,LenInfoBuffer 'Get string version info
  sOriginalFilename="Original filename: "+Peek$(lpInfoBuffer,LenInfoBuffer-1)                                 'Without NULL termination
  '
  VerQueryValue ByVal StrPtr(sVersion),"\StringFileInfo\040904E4\LegalCopyright",lpInfoBuffer,LenInfoBuffer  'Get string version info
  sLegalCopyright="Copyright: "+Peek$(lpInfoBuffer,LenInfoBuffer-1)                                          'Without NULL termination
  '
  VerQueryValue ByVal StrPtr(sVersion),"\StringFileInfo\040904E4\CompanyName",lpInfoBuffer,LenInfoBuffer     'Get string version info
  sCompanyName="Company name: "+Peek$(lpInfoBuffer,LenInfoBuffer-1)                                          'Without NULL termination
  '
  VerQueryValue ByVal StrPtr(sVersion),"\StringFileInfo\040904E4\FileVersion",lpInfoBuffer,LenInfoBuffer     'Get string version info
  sFileVersion="Version: "+Peek$(lpInfoBuffer,LenInfoBuffer-1)                                               'Without NULL termination
  '
  szBuffer=sFileComment+Chr$(13,13)+sOriginalFilename+Chr$(13)+sFileVersion+Chr$(13)+sLegalCopyright+Chr$(13)+sCompanyName+_
           Chr$(13,13)+"The editor is GPL Freeware."+Chr$(13)+"Updates: www.rowalt.de/pc/ --> FreeBasic/PowerBasic --> Tools"
  '
  MessageBox hwndParent,szBuffer,"About "+$APP_NAME_SHORT,%MB_ICONINFORMATION
End Sub
'***************************************************************************************************************************************

'BESETTINGS (don't change!):
'BECURSOR=10A
'BETOGGLE=10000000000000000000000000000000000000000