Announcement

Collapse
No announcement yet.

Help Needed Interpreting C Requirements

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help Needed Interpreting C Requirements

    I've not having much success in creating a PowerBASIC DLL that provides external lexer capabilities to the Scintilla control. The limited Scintilla documentation is written in C and my C skills are not good enough to interpret what the C documentation is asking for. It's the interface, not the lexing code itself, that I need help with. The code framework I've written (below) compiles, but that's about it.

    Scintilla documentation is very sparse, with only this guidance:

    Scintilla also supports external lexers. These are DLLs (on Windows) or .so modules (on GTK+/Linux) that export four functions: GetLexerCount, GetLexerName, Lex and Fold. See externalLexer.cxx for more.
    I'd be interested in hearing from someone who has done this, or who can help interpret the C file "externallexer.cxx".

    I've search (a lot) on the web, with surprisingly no success in finding examples of writing the DLL Scintilla needs.

    Here is a copy of externallexer.cxx, followed by my attempt to create a PowerBASIC DLL framework.

    Code:
    // Scintilla Source Code edit Control
    /** @file ExternalLexer.cxx
     ** Support external lexers in DLLs.
     **/
    // Copyright 2001 Simon Steele <[email protected]>, portions copyright Neil Hodgson.
    // The License.txt file describes the conditions under which this software may be distributed.
    
    #Include <stdlib.h>
    #Include <stdio.h>
    #Include <String.h>
    #Include <ctype.h>
    
    #Include <String>
    
    #Include "Platform.h"
    
    #Include "Scintilla.h"
    
    #Include "SciLexer.h"
    #Include "PropSet.h"
    #Include "Accessor.h"
    #Include "DocumentAccessor.h"
    #Include "KeyWords.h"
    #Include "ExternalLexer.h"
    
    #ifdef SCI_NAMESPACE
    using namespace Scintilla;
    #EndIf
    
    LexerManager *LexerManager::theInstance = NULL;
    
    //------------------------------------------
    //
    // ExternalLexerModule
    //
    //------------------------------------------
    
    char **WordListsToStrings(WordList *Val[]) {
        Int Dim = 0;
        While (Val[Dim])
            Dim++;
        char **wls = New char * [Dim + 1];
        For (Int i = 0; i < Dim; i++) {
            std::String words;
            words = "";
            For (Int n = 0; n < Val[i]->Len; n++) {
                words += Val[i]->words[n];
                If (n != Val[i]->Len - 1)
                    words += " ";
            }
            wls[i] = New char[words.length() + 1];
            strcpy(wls[i], words.c_str());
        }
        wls[Dim] = 0;
        Return wls;
    }
    
    void DeleteWLStrings(char *strs[]) {
        Int Dim = 0;
        While (strs[Dim]) {
            Delete strs[Dim];
            Dim++;
        }
        Delete [] strs;
    }
    
    void ExternalLexerModule::Lex(unsigned Int startPos, Int lengthDoc, Int initStyle,
                                  WordList *keywordlists[], Accessor &styler) const {
        If (!fneLexer)
            Return ;
    
        char **kwds = WordListsToStrings(keywordlists);
        char *ps = styler.GetProperties();
    
        // The accessor passed in is always a DocumentAccessor so this cast AND the subsequent
        // access will work. Can Not use the stricter dynamic_cast as that requires RTTI.
        DocumentAccessor &da = static_cast<DocumentAccessor &>(styler);
        WindowID wID = da.GetWindow();
    
        fneLexer(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps);
    
        Delete ps;
        DeleteWLStrings(kwds);
    }
    
    void ExternalLexerModule::Fold(unsigned Int startPos, Int lengthDoc, Int initStyle,
                                   WordList *keywordlists[], Accessor &styler) const {
        If (!fneFolder)
            Return ;
    
        char **kwds = WordListsToStrings(keywordlists);
        char *ps = styler.GetProperties();
    
        // The accessor passed in is always a DocumentAccessor so this cast AND the subsequent
        // access will work. Can Not use the stricter dynamic_cast as that requires RTTI.
        DocumentAccessor &da = static_cast<DocumentAccessor &>(styler);
        WindowID wID = da.GetWindow();
    
        fneFolder(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps);
    
        Delete ps;
        DeleteWLStrings(kwds);
    }
    
    void ExternalLexerModule::SetExternal(ExtLexerFunction fLexer, ExtFoldFunction fFolder, Int index) {
        fneLexer = fLexer;
        fneFolder = fFolder;
        externalLanguage = index;
    }
    
    //------------------------------------------
    //
    // LexerLibrary
    //
    //------------------------------------------
    
    LexerLibrary::LexerLibrary(const char *ModuleName) {
        // Initialise some members...
        first = NULL;
        last = NULL;
    
        // Load the DLL
        lib = DynamicLibrary::Load(ModuleName);
        If (lib->IsValid()) {
            m_sModuleName = ModuleName;
            //Cannot use reinterpret_cast because: ANSI C++ forbids casting between pointers to functions AND objects
            GetLexerCountFn GetLexerCount = (GetLexerCountFn)(sptr_t)lib->FindFunction("GetLexerCount");
    
            If (GetLexerCount) {
                ExternalLexerModule *lex;
                LexerMinder *lm;
    
                // Find functions in the DLL
                GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName");
                ExtLexerFunction Lexer = (ExtLexerFunction)(sptr_t)lib->FindFunction("Lex");
                ExtFoldFunction Folder = (ExtFoldFunction)(sptr_t)lib->FindFunction("Fold");
    
                // Assign a buffer For the lexer Name.
                char lexname[100];
                strcpy(lexname, "");
    
                Int nl = GetLexerCount();
    
                For (Int i = 0; i < nl; i++) {
                    GetLexerName(i, lexname, 100);
                    lex = New ExternalLexerModule(SCLEX_AUTOMATIC, NULL, lexname, NULL);
    
                    // Create a LexerMinder so we don't leak the ExternalLexerModule...
                    lm = New LexerMinder;
                    lm->self = lex;
                    lm->Next = NULL;
                    If (first != NULL) {
                        last->Next = lm;
                        last = lm;
                    } Else {
                        first = lm;
                        last = lm;
                    }
    
                    // The external lexer needs to know how to Call into its DLL to
                    // Do its lexing AND folding, we tell it here. Folder may be null.
                    lex->SetExternal(Lexer, Folder, i);
                }
            }
        }
        Next = NULL;
    }
    
    LexerLibrary::~LexerLibrary() {
        Release();
        Delete lib;
    }
    
    void LexerLibrary::Release() {
        //TODO maintain a list of lexers created, AND Delete them!
        LexerMinder *lm;
        LexerMinder *lmNext;
        lm = first;
        While (NULL != lm) {
            lmNext = lm->Next;
            Delete lm->self;
            Delete lm;
            lm = lmNext;
        }
    
        first = NULL;
        last = NULL;
    }
    
    //------------------------------------------
    //
    // LexerManager
    //
    //------------------------------------------
    
    /// Return the single LexerManager Instance...
    LexerManager *LexerManager::GetInstance() {
        If (!theInstance)
            theInstance = New LexerManager;
        Return theInstance;
    }
    
    /// Delete any LexerManager Instance...
    void LexerManager::DeleteInstance() {
        Delete theInstance;
        theInstance = NULL;
    }
    
    /// protected constructor - this is a singleton...
    LexerManager::LexerManager() {
        first = NULL;
        last = NULL;
    }
    
    LexerManager::~LexerManager() {
        Clear();
    }
    
    void LexerManager::Load(const char *path) {
        LoadLexerLibrary(path);
    }
    
    void LexerManager::LoadLexerLibrary(const char *module) {
        For (LexerLibrary *ll = first; ll; ll= ll->Next) {
            If (strcmp(ll->m_sModuleName.c_str(), module) == 0)
                Return;
        }
        LexerLibrary *lib = New LexerLibrary(module);
        If (NULL != first) {
            last->Next = lib;
            last = lib;
        } Else {
            first = lib;
            last = lib;
        }
    }
    
    void LexerManager::Clear() {
        If (NULL != first) {
            LexerLibrary *cur = first;
            LexerLibrary *Next;
            While (cur) {
                Next = cur->Next;
                Delete cur;
                cur = Next;
            }
            first = NULL;
            last = NULL;
        }
    }
    
    //------------------------------------------
    //
    // LexerManager
    //
    //------------------------------------------
    
    LMMinder::~LMMinder() {
        LexerManager::DeleteInstance();
    }
    
    LMMinder minder;
    And here is PowerBASIC code I wrote to create the framework for the DLL. I've included the 4 functions Scintilla documentation says I need, but without being able to interpret their example C file, I'm unable to flesh out my own code.

    Code:
    'Compilable Example
    #Compile DLL "CustomPowerBASICLexer"     'use filename "CustomPowerBASICLexer.dll"
    
    Function PBLibMain() As Long
       'optional - is called by LoadLibrary() when DLL is loaded & unloaded
    End Function
    
    ' Exported Functions ----------------------------------------
    Function GetLexerCount Alias "GetLexerCount" () Export As Long
       'no idea what this function is for
       Function = 1            'place holder
    End Function
    
    Function GetLexerName Alias "GetLexerName" () Export As String
       'I assume this function is to return the name of the language to calling program
       Function = "custompowerbasic"      'arbitrary name
    End Function
    
    Function Lex Alias "Lex" (startPos As Long, _
                 LengthDoc As Long, _
                 initStyle as Long, _
                 KeyWords As String, _   'first element of array
                 Styler As Long _
                 ) Export As Long
       'code goes here
    End Function
    
    Function Fold Alias "Fold" (startPos As Long, _
                  LengthDoc As Long, _ 
                  initStyle As Long, _
                  KeyWords As String, _  'first element of array
                  Styler As Long _
                  ) Export As Long
       'code goes here
    End Function
    My framework compiles without error and when I use it an app, I get no errors. I was hoping that a Scintilla "GetLexerLanguage" message would return "customerpowerbasic" (from code above), but instead it returns "null".

    I'm continuing to work with it, but if anyone has some insight, please let me know.

    Finally, here's my sample PowerBASIC app that tries to load/use the DLL built using the code above:

    Code:
    'Compilable Example:
    #Compile Exe
    #Dim All
    #Debug Error On     'catch array/pointer errors - OFF in production
    #Debug Display On   'display untrapped errors   - OFF in production
    #Include "Win32API.inc"
    #Include "scintilla_gb.inc"
    
    %ID_Sci = 1000
    Global hDlg, hSci, hLib As DWord
    
    Function PBMain() As Long
       hLib = LoadLibrary("SCILEXER.DLL")
       Dialog New Pixels, 0, "Scintilla: DLL Lexer",300,300,200,150, %WS_OverlappedWindow To hDlg
       Control Add "Scintilla", hDlg, %ID_Sci, "", 10,10,180,130, %WS_Child Or %WS_Visible
       Control Handle hDlg, %ID_Sci To hSci     'get handle to Scintilla window
       Dialog Show Modal hDlg Call DlgProc
    End Function
    
    CallBack Function DlgProc() As Long
       Select Case CB.Msg
          Case %WM_InitDialog
             InitializeSci
          Case %WM_Destroy
             If hLib Then FreeLibrary hLib             ' Free the Scintilla library
       End Select
    End Function
    
    Sub InitializeSci
       Local txt As String
       txt = "Select Case" + $CrLf
       txt = txt + "'   Case " + Chr$(34) + "cat" + Chr$(34) + $CrLf
       txt = txt + "'   Case " + Chr$(34) + "dog" + Chr$(34) + $CrLf
       txt = txt + "End Select" + Chr$(0)
       SendMessage(hSci, %SCI_SetText,         0, StrPTR(txt))       'set example text
       SendMessage hSci, %SCI_SetMarginWidthN, 0, 20                 'display line numbers
    
       txt = "CustomPowerBASICLexer.dll"
       SendMessage hSci, %SCI_LoadLexerLibrary, 0, StrPTR(txt)
       txt = "custompowerbasic"
       SendMessage hSci, %SCI_SetLexerLanguage, 0, StrPTR(txt)
       txt = String$(100," ")
       SendMessage hSci, %SCI_GetLexerLanguage, 0, StrPTR(txt)
       MsgBox txt
    End Sub
    Last edited by Gary Beene; 24 Jun 2010, 04:17 PM.

  • #2
    To begin with, you need to aliase the exported functions, e.g.

    Code:
    Function GetLexerCount ALIAS "GetLexerCount" () Export As Long
    Otherwise, the PB compiler will capitalize the name.
    Last edited by José Roca; 27 Jun 2010, 09:18 AM. Reason: Spelling correction
    Forum: http://www.jose.it-berater.org/smfforum/index.php

    Comment


    • #3
      Jose, thank you for that correction. I've update the posted code accordingly.

      My code still isn't right, but it's one step closer.

      Comment


      • #4
        Well, I'm learning a bit more. I changed the PBLibMain code to this, so I could see entry/exit from the DLL.

        Code:
        Function PBLibMain() As Long
           Static flag As Long
              If Flag = 0 Then
              MsgBox "I'm in!"
              Flag = 1
           Else
              If Err Then MsgBox "Error, too!" + Error$(Err)
              MsgBox "I'm leaving!"
           End If
        End Function
        When I start my program, it seems to enter the DLL just fine.

        But when these statements are executed, the DLL exits, with no program errror and no Scintilla error (it has limited error message capabilities).

        Code:
           txt = "CustomPowerBASICLexer.dll"
           SendMessage hSci, %SCI_LoadLexerLibrary, 0, StrPTR(txt)
        So I'm assuming that as Scintilla tries to access functions in the DLL, something goes wrong. I'm surprised the DLL exits, rather than getting a program error.

        But I'm guessing all this means that my function declarations are wrong.

        Here are the C documentation for the function, and the PowerBASIC interpretation I made.

        Code:
        --- GetLexerCount----------------------------------
        int EXT_LEXER_DECL GetLexerCount();
        
        Function GetLexerCount Alias "GetLexerCount" () Export As Long
        
        
        --- GetLexerName-----------------------------------
        void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int  buflength);
         
        Function GetLexerName Alias "GetLexerName" (Index As Long, lName As String, iLength As Long) Export As String
        
        
        --- Lex-----------------------------------
        void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int  length, int initStyle, char *words[],
             WindowID window, char *props);
         
        Function Lex Alias "Lex" (startPos As Long, _
                     LengthDoc As Long, _
                     initStyle As Long, _
                     KeyWords As String, _   'first element of array
                     Styler As Long _
                     ) Export As Long
        
        
        ---Fold-----------------------------------
        void EXT_LEXER_DECL Fold(unsigned int lexer, unsigned int startPos, int  length,  int initStyle, char *words[], WindowID window, char *props);
        
        Function Fold Alias "Fold" (startPos As Long, _
                      LengthDoc As Long, _
                      initStyle As Long, _
                      KeyWords As String, _  'first element of array
                      Styler As Long _
                      ) Export As Long
        I found this helpful, but short description of how to add an external lexer to Scintilla. That's where I got the above C function definitions.
        Add External Lexer to Scintilla:
        This document assumes you know how to create a lexer. It only covers information specific to making the changes necessary for that lexer to work as an external lexer.
        The lexer must export 4 functions (On Windows, it is necessary to create a module definition file to export the symbols correctly). Below are the proto-types for those functions (ExternalLexer.h must be included so that EXT_LEXER_DECL can be resolved):
        void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[],
        WindowID window, char *props);
        int EXT_LEXER_DECL GetLexerCount();
        void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength);
        void EXT_LEXER_DECL Fold(unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[],
        WindowID window, char *props);
        Lex - This function is called whenever lexing needs to be done. The first thing you may notice is the lack of an Accessor object to style with. A WindowAccessor object can be created from the WindowID and props objects. A PropSet object must be created from props, first, then that PropSet and the WindowID are used to create a WindowAccessor. You will also need to create your own WordList. (The last row in the words array is a NULL pointer, so you can safely read 1 past the last row to determine how many rows there are). Once you have the WordList and Accessor, you can pass them to your lexing function just like using a built-in lexer. The only other difference is you need to call Accessor::Flush() sometime before Lex returns, or not all text may be updated. This is due to Scintilla's buffering.
        GetLexerCount - This returns the number of individual lexers you want to export from your module.
        GetLexerName - Fill in the name field with the name of the lexer. This is how it is later identified in SciTE properties.
        Fold - The function called whenever SciTE requests folding be performed. The same information found in Lex for creating a WindowAccessor apply here, too.

        Comment


        • #5
          >KeyWords As String, _ 'first element of array

          A c '* Char' is not a PB STRING. What's passed is the address of a null-terminated string, so there are lots of options for the PB DECLARE.

          "BYVAL pAZ AS ASCIIZ PTR" will work. So will " [BYREF] sz AS ASCIIZ."

          MCM
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            I'm just eyeballing this, so it may need adjustment, but this should get you a bit closer.

            Code:
            SUB Lex ALIAS "Lex" (BYVAL lexer AS DWORD, BYVAL startPos AS DWORD, _
               BYVAL length AS LONG, BYVAL initStyle AS LONG, _
               BYVAL words AS ASCIIZ PTR, window AS ANY, props AS ASCIIZ) EXPORT
            
            FUNCTION GetLexerCount ALIAS "GetLexerCount" () EXPORT AS LONG
            
            SUB GetLexerName ALIAS "GetLexerName" (BYVAL Index AS DWORD, _
               name AS ASCIIZ, BYVAL buflength AS LONG) EXPORT
            
            SUB Fold ALIAS "Fold" (BYVAL lexer AS DWORD, BYVAL startPos AS DWORD, _
               BYVAL length AS LONG, BYVAL initStyle AS LONG, _
               BYVAL words AS ASCIIZ PTR, window AS ANY, props AS ASCIIZ) EXPORT
            I don't see a definition for WindowID offhand, so I went with AS ANY. There may be a better choice.

            Comment


            • #7
              Thanks MCM and Tom,

              I've made the changes, and rewritten the code so it's easier to compare the C and PowerBASIC:

              Code:
              Function GetLexerCount Alias "GetLexerCount" () Export As Long  'Int EXT_LEXER_DECL GetLexerCount();
                 Function = 1
              End Function  
              
              Sub GetLexerName Alias "GetLexerName" ( _      'void EXT_LEXER_DECL GetLexerName(
                           ByVal Index As DWord, _           'unsigned Int Index, 
                           ByVal langName as AsciiZ PTR, _   'char *Name,     : alternate: Name As AsciiZ
                           ByVal bufLength As Long _         'int  buflength
                           ) Export 
                 @langName = "custompowerbasic"
              End Sub
              
              Sub Lex Alias "Lex" ( _                      'void EXT_LEXER_DECL Lex(
                           ByVal lexer As DWord, _         'unsigned Int lexer, 
                           ByVal startPos As DWord, _      'unsigned Int startPos, 
                           ByVal LengthDoc As Long, _      'int  length, 
                           Byval initStyle as Long, _      'int initStyle,
                           ByVal Words As AsciiZ Ptr, _    'char *words[],       : pointer to first element of string array
                           ByVal wID As DWord, _           'WindowID Window,     : alternate: wID As Any
                           ByVal Props As AsciiZ Ptr _     'char *props          : alternate: props As AsciiZ  : pointer to ASCIIZ string
                           ) Export
              End Sub
              
              Sub Fold Alias "Fold" ( _                   'void EXT_LEXER_DECL Fold(
                          ByVal lexer As DWord, _         'unsigned Int lexer, 
                          ByVal startPos As DWord, _      'unsigned int startPos,
                          ByVal LengthDoc As Long, _      'int  length,  
                          ByVal initStyle As Long, _      'int initStyle, 
                          ByVal Words As AsciiZ Ptr, _    'char *words[],    : pointer to first element of string array
                          ByVal wID As DWord, _           'WindowID Window,  : alternate:  wID As Any
                          ByVal Props As AsciiZ Ptr _     ' char *props      : alternate:  props As AsxiiZ   : pointer to ASCIIZ string
                          ) Export
              End Sub
              Interestingly, Tom, when I change the wID declaration to "wID as Any", I get a compiler error "Undefined Type". I wasn't expecting that, as I thought ANY was just fine.

              Even with these changes the DLL still drops out when I execute the Scintilla message %SCI_LoadLexerLibrary. But thanks to your help, I hope I've almost past the declaration problems. I'll experiment some more.

              Comment


              • #8
                don't see a definition for WindowID offhand, so I went with AS ANY. There may be a better choice.
                I don't think 'AS ANY' will work. That param is not a "* WindowID" so it is more than likely NOT looking for an address, it's probably looking for a value.

                Since this is a "GUI" application and I don't see any references to a window by handle, I'd guess "BYVAL hWnd AS LONG" would be a good starting point ...unless that control returns some kind of "ID" (handle) when created... and I'd guess that would be something BYVAL, too.

                MCM
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  Oops. I'm too used to thinking in terms of DECLARE, where AS ANY is fine.

                  BYVAL window AS DWORD

                  ...may be a good placeholder until you can find out what a WindowID type is.

                  Comment


                  • #10
                    Thanks again, guys.

                    I also posted a message in the Scintilla-Interest Google Group to see if I can rouse the attention of someone there who might have direct experience in a non-C version of an external lexer.

                    I also got in touch with Ronald Walter, whose name is on the PowerBASIC lexer built into Scintilla. Unfortunately he also had not worked with the DLL version of a lexer.

                    Comment


                    • #11
                      The PB DLL lexer. Save as PBSciLex.bas:

                      Code:
                      #COMPILE DLL
                      #DIM ALL
                      
                      #INCLUDE "windows.inc"
                      
                      ' =======================================================================================
                      ' int EXT_LEXER_DECL GetLexerCount();
                      ' =======================================================================================
                      FUNCTION GetLexerCount ALIAS "GetLexerCount" () EXPORT AS LONG
                      
                         OutputDebugString "GetLexerCount"
                      
                         FUNCTION = 1
                      
                      END FUNCTION
                      ' =======================================================================================
                      
                      ' =======================================================================================
                      ' void EXT_LEXER_DECL GetLexerName (unsigned int Index, char *name, int  buflength);
                      ' =======================================================================================
                      SUB GetLexerName ALIAS "GetLexerName" (BYVAL Index AS DWORD, _
                         BYREF szName AS ASCIIZ, BYVAL buflength AS LONG) EXPORT
                      
                         OutputDebugString "GetLexerName"
                      
                         IF bufLength > 0 AND Index = 0 THEN szName = LEFT$("pblexer", buflength - 1) & $NUL
                      
                      END SUB
                      ' =======================================================================================
                       
                      ' =======================================================================================
                      ' void EXT_LEXER_DECL Lex (unsigned int lexer, unsigned int startPos, int length, 
                      '    int initStyle, char *words[], WindowID window, char *props);
                      ' =======================================================================================
                       
                      SUB Lex ALIAS "Lex" (BYVAL lexer AS DWORD, BYVAL startPos AS DWORD, _
                         BYVAL length AS LONG, BYVAL initStyle AS LONG, _
                         BYVAL words AS ASCIIZ PTR, BYVAL wID AS DWORD, BYREF props AS ASCIIZ) EXPORT
                      
                         OutputDebugString "Lex"
                      
                      END SUB
                      ' =======================================================================================
                      
                      ' =======================================================================================
                      ' void EXT_LEXER_DECL Fold (unsigned int lexer, unsigned int startPos, int length,
                      '   int initStyle, char *words[], WindowID window, char *props);
                      ' =======================================================================================
                      SUB Fold ALIAS "Fold" (BYVAL lexer AS DWORD, BYVAL startPos AS DWORD, _
                         BYVAL length AS LONG, BYVAL initStyle AS LONG, _
                         BYVAL words AS ASCIIZ PTR, BYVAL wID AS DWORD, BYREF props AS ASCIIZ) EXPORT
                      
                         OutputDebugString "Fold"
                      
                      END SUB
                      ' =======================================================================================
                      Forum: http://www.jose.it-berater.org/smfforum/index.php

                      Comment


                      • #12
                        The test program. Save it as SciTest.bas:

                        Code:
                        #COMPILE EXE
                        #DIM ALL
                        #DEBUG ERROR ON
                        #INCLUDE "Scintilla.inc"
                        #INCLUDE "SciLexer.inc"
                        
                        '#define SCI_GETLEXERLANGUAGE 4012
                        %SCI_GETLEXERLANGUAGE = 4012
                        
                        %ID_SCI = 100
                        
                        ' ========================================================================================
                        ' Main
                        ' ========================================================================================
                        FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
                        
                           LOCAL hWndMain    AS DWORD
                           LOCAL hCtl        AS DWORD
                           LOCAL hFont       AS DWORD
                           LOCAL wcex        AS WNDCLASSEX
                           LOCAL szClassName AS ASCIIZ * 80
                           LOCAL rc          AS RECT
                           LOCAL szCaption   AS ASCIIZ * 255
                           LOCAL nLeft       AS LONG
                           LOCAL nTop        AS LONG
                           LOCAL nWidth      AS LONG
                           LOCAL nHeight     AS LONG
                        
                           ' Load the Scintilla library
                           LOCAL hLib AS DWORD
                           hLib = LoadLibrary("SCILEXER.DLL")
                           IF hLib = 0 THEN EXIT FUNCTION
                        
                           hFont = GetStockObject(%ANSI_VAR_FONT)
                        
                           ' Register the window class
                           szClassName        = "MyClassName"
                           wcex.cbSize        = SIZEOF(wcex)
                           wcex.style         = %CS_HREDRAW OR %CS_VREDRAW
                           wcex.lpfnWndProc   = CODEPTR(WndProc)
                           wcex.cbClsExtra    = 0
                           wcex.cbWndExtra    = 0
                           wcex.hInstance     = hInstance
                           wcex.hCursor       = LoadCursor (%NULL, BYVAL %IDC_ARROW)
                           wcex.hbrBackground = %COLOR_3DFACE + 1
                           wcex.lpszMenuName  = %NULL
                           wcex.lpszClassName = VARPTR(szClassName)
                           wcex.hIcon         = LoadIcon (%NULL, BYVAL %IDI_APPLICATION) ' Sample, if resource icon: LoadIcon(hInst, "APPICON")
                           wcex.hIconSm       = LoadIcon (%NULL, BYVAL %IDI_APPLICATION) ' Remember to set small icon too..
                           RegisterClassEx wcex
                        
                           ' Window caption
                           szCaption = "SDK Main Window"
                        
                           ' Retrieve the size of the working area
                           SystemParametersInfo %SPI_GETWORKAREA, 0, BYVAL VARPTR(rc), 0
                        
                           ' Calculate the position and size of the window
                           nWidth  = (((rc.nRight - rc.nLeft)) + 2) * 0.75   ' 75% of the client screen width
                           nHeight = (((rc.nBottom - rc.nTop)) + 2) * 0.70   ' 70% of the client screen height
                           nLeft   = ((rc.nRight - rc.nLeft) \ 2) - nWidth \ 2
                           nTop    = ((rc.nBottom - rc.nTop) \ 2) - (nHeight \ 2)
                        
                           ' Create a window using the registered class
                           hWndMain = CreateWindowEx(%WS_EX_CONTROLPARENT, _           ' extended style
                                                     szClassName, _                    ' window class name
                                                     szCaption, _                      ' window caption
                                                     %WS_OVERLAPPEDWINDOW OR _
                                                     %WS_CLIPCHILDREN, _               ' window styles
                                                     nLeft, _                          ' initial x position
                                                     nTop, _                           ' initial y position
                                                     nWidth, _                         ' initial x size
                                                     nHeight, _                        ' initial y size
                                                     %NULL, _                          ' parent window handle
                                                     0, _                              ' window menu handle
                                                     hInstance, _                      ' program instance handle
                                                     BYVAL %NULL)                      ' creation parameters
                        
                           hCtl = CreateWindowEx(0, "BUTTON", "&Close", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_FLAT, _
                                  0, 0, 0, 0, hWndMain, %IDCANCEL, hInstance, BYVAL %NULL)
                           IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0
                        
                           ' Add an instance of the Scintilla control
                           LOCAL hSci AS DWORD
                           hSci = CreateWindowEx(0, "Scintilla", "", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %WS_BORDER, _
                                  0, 0, 0, 0, hWndMain, %ID_SCI, hInstance, BYVAL %NULL)
                        
                           LOCAL txt AS STRING
                           txt = "Select Case" + $CRLF
                           txt = txt + "'   Case " & $DQ & "cat" & $DQ & $CRLF
                           txt = txt + "'   Case " & $DQ & "dog" & $DQ & $CRLF
                           txt = txt + "End Select" & $CRLF
                           SendMessage(hSci, %SCI_SETTEXT,         0, STRPTR(txt))       'set example text
                           SendMessage hSci, %SCI_SETMARGINWIDTHN, 0, 20                 'display line numbers
                        
                           ' Set the PB external lexer
                           
                           txt = EXE.PATH$ & "PBSciLex.dll"
                           SendMessage hSci, %SCI_LOADLEXERLIBRARY, 0, STRPTR(txt)
                           txt = "pblexer"
                           SendMessage hSci, %SCI_SETLEXERLANGUAGE, 0, STRPTR(txt)
                           txt = String$(100," ")
                           SendMessage hSci, %SCI_GETLEXERLANGUAGE, 0, STRPTR(txt)
                           MSGBOX txt
                        
                           ' Show the window
                           ShowWindow hWndMain, nCmdShow
                           UpdateWindow hWndMain
                        
                           ' Message handler loop
                           LOCAL uMsg AS tagMsg
                           WHILE GetMessage(uMsg, %NULL, 0, 0)
                              IF ISFALSE IsDialogMessage(hWndMain, uMsg) THEN
                                 TranslateMessage uMsg
                                 DispatchMessage uMsg
                              END IF
                           WEND
                        
                           ' Unload Scintilla
                           IF hLib THEN FreeLibrary hLib
                        
                           FUNCTION = uMsg.wParam
                        
                        END FUNCTION
                        ' ========================================================================================
                        
                        ' ========================================================================================
                        ' Main Window procedure
                        ' ========================================================================================
                        FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
                        
                           LOCAL rc AS RECT
                        
                           SELECT CASE wMsg
                        
                              CASE %WM_CREATE
                                 ' -------------------------------------------------------
                                 ' A good place to initiate things, declare variables,
                                 ' create controls and read/set settings from a file, etc.
                                 ' -------------------------------------------------------
                        
                              CASE %WM_SIZE
                                 IF wParam <> %SIZE_MINIMIZED THEN
                                    GetClientRect hWnd, rc
                                    MoveWindow GetDlgItem(hWnd, %ID_SCI), 10, 10, (rc.nRight - rc.nLeft) - 20, (rc.nBottom - rc.nTop) - 55, %TRUE
                                    MoveWindow GetDlgItem(hWnd, %IDCANCEL), (rc.nRight - rc.nLeft) - 95, (rc.nBottom - rc.nTop) - 35, 75, 23, %TRUE
                                 END IF
                        
                              CASE %WM_COMMAND
                                 SELECT CASE LO(WORD, wParam)
                                    CASE %IDCANCEL
                                       IF HI(WORD, wParam) = %BN_CLICKED THEN
                                          SendMessage hWnd, %WM_CLOSE, 0, 0
                                          EXIT FUNCTION
                                       END IF
                                 END SELECT
                        
                              CASE %WM_SYSCOMMAND
                                 ' Capture this message and send a WM_CLOSE message
                                 IF (wParam AND &HFFF0) = %SC_CLOSE THEN
                                    SendMessage hWnd, %WM_CLOSE, 0, 0
                                    EXIT FUNCTION
                                 END IF
                        
                              CASE %WM_DESTROY
                                 PostQuitMessage 0
                                 EXIT FUNCTION
                        
                           END SELECT
                        
                           FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
                        
                        END FUNCTION
                        ' ========================================================================================
                        NOTE: Uses my own Windows API Headers. Change whatever you need if you don't use them.
                        Last edited by José Roca; 25 Jun 2010, 05:01 PM.
                        Forum: http://www.jose.it-berater.org/smfforum/index.php

                        Comment

                        Working...
                        X