RadASM Custom Controls - mrfearless/RadASM2 GitHub Wiki

RadASM Custom Controls

Custom controls are dynamic link library files that add additional functionality to RadASM and to programs that make use of them. They can add new types of UI interaction that speeds up development for developers and potentially adds an ease of use quality to programs, for users that use them.

Custom controls can be added to RadASM in two ways: by using the menu Option->Custom Controls and browsing for the the appropriate dll file that hosts the controls

images/custctrl_opt.gif

or by manual editing the RadASM.ini file and adding the dll file reference to the CustCtrl section. Optionally the number of controls hosted in the dll file can be specified by manually editing the CustCtrl entry and appending a comma and the count of the number of controls. Below is an example of a CustCtrl entry:

[CustCtrl]
1=RACad.dll,1
2=RAEdit.dll,1
3=RAHexEd.dll,1
4=RAGrid.dll,1
5=SprSht.dll,1
6=WBDll.dll,1
7=RAFile.dll,1
8=RACodeComplete.dll,2
9=hl.dll,1
10=RAGraph.dll,1
11=RAVideo.dll,1

The maximum number of custom controls was 32 and was raised to 64 with v2.2.2.3 of RadASM. A number of custom controls are already included with RadASM packages and these controls are stored in the same folder as RadASM.exe by default.

Custom Control DLL

A custom control is a standard win32 dynamic link library file. The RadASM custom control dll requires at least two functions exported for it to be usable with RadASM (after it has been added to the CustCtrl section via manual entry or via menu option). These two functions are:

  • GetDef
  • GetDefEx

The prototypes for both functions are as follows:

GetDef    PROTO :DWORD ; nInx
GetDefEx  PROTO :DWORD ; nInx

Exported Functions

If you are developing the custom control using assembly (and using RadASM) you will also need to specify in the definition file the required functions for exporting, for example:

LIBRARY MyControl
EXPORTS GetDef
        GetDefEx

Additionally the dll will require the DllEntry function, and in this you should make a call to a function to register your controls class. Here is an example of the DllEntry function:

DllEntry PROC PUBLIC hInst:HINSTANCE, reason:DWORD, reserved1:DWORD
    .IF reason == DLL_PROCESS_ATTACH
        push hInst
        pop hInstance
        Invoke InstallControl, hInst, TRUE
    .ELSEIF reason == DLL_PROCESS_DETACH
    .ENDIF
    mov eax,TRUE
    ret
DllEntry ENDP

Registering The Custom Control Class

The above example shows a call to an InstallControl function. It might look something like this example:

InstallControl PROC PUBLIC hInst:HINSTANCE, fGlobal:DWORD
    LOCAL wc:WNDCLASSEX

    mov wc.cbSize, SIZEOF WNDCLASSEX
    mov wc.style, CS_HREDRAW or CS_VREDRAW or CS_PARENTDC or CS_DBLCLKS
    .if fGlobal
        mov wc.style, CS_HREDRAW or CS_VREDRAW or CS_PARENTDC or CS_DBLCLKS or CS_GLOBALCLASS
    .endif
    mov wc.lpfnWndProc, offset MyControlMainProc
    mov eax, NULL
    mov wc.cbClsExtra, eax
    mov wc.hbrBackground, eax
    mov wc.lpszMenuName, eax
    mov wc.hIcon, eax
    mov wc.hIconSm, eax
    mov wc.cbWndExtra, 4
    mov eax, hInst
    mov wc.hInstance, eax
    mov hInstance, eax
    mov wc.lpszClassName, offset szMyControlClassName
    Invoke LoadCursor, NULL, IDC_ARROW
    mov wc.hCursor, eax
    Invoke RegisterClassEx, Addr wc
    ret
InstallControl ENDP

Whatever the name of the function, the function used to register your control should include code to store the class information for your control in a WNDCLASSEX structure. The WNDCLASSEX structure is then used in a call to the RegisterClassEx function. The lpfnWndProc field of the WNDCLASSEX has to point to the controls main window procedure, which is where the main controls functionality is handled along with any required windows events (WM_ messages) and painting of the control.

Once your control's class is registered then the control can be created by referencing the classname in calls to CreateWindow/CreateWindowEx or via a dialog creating its child controls from resources that reference the control's classname.

GetDef and GetDefEx functions

The GetDef function was used by earlier versions of RadASM v1.2.0.5 until RadASM v2.1.0.4 when the GetDefEx function was introduced to extend the functionality. GetDef remains to provide backward compatible support for older custom controls.

GetDef has one DWORD parameter, which is nInx, an index to the control hosted in the dll to fetch information for. GetDef must return in eax a valid pointer to a CCDEF structure for the specified index (nInx parameter) or 0 otherwise.

GetDefEx has one DWORD parameter, which is nInx, an index to the control hosted in the dll to fetch information for. GetDefEx must return in eax a valid pointer to a CCDEFEX structure for the specified index (nInx parameter) or 0 otherwise.

Typically the GetDef and GetDefEx functions will look like the following example (for 1 hosted control)

GetDef PROC nInx:DWORD
    mov eax, nInx
    .IF !eax
        Invoke LoadBitmap, hInstance, IDB_BMP ; Load the toolbox bitmap
        mov ccdef.hbmp, eax ; Save handle of bitmap to ccdef struct
        lea eax, ccdef ; Return pointer to inited ccdef struct
    .ELSE
        xor eax, eax
    .ENDIF
    ret
GetDef ENDP

GetDefEx PROC public nInx:DWORD
    mov eax, nInx
    .IF !eax
        Invoke LoadBitmap, hInstance, IDB_BMP ; Load the toolbox bitmap
        mov ccdefex.hbmp, eax ; Save handle of bitmap to ccdefex struct
        lea eax, ccdefex ; Return pointer to inited ccdefex struct
    .ELSE
        xor eax, eax
    .ENDIF
    ret
GetDefEx ENDP

CCDEF and CCDEFEX structures

The CCDEF and CCDEFEX structures store information relating to each control hosted in the dll file. The CCDEF structure is used with the GetDef function and the CCDEFEX structure is used with the GetDefEx function. Both structures share mostly the same fields with a few exceptions - which are detailed below.

For a dll file that host multiple controls, additional CCDEF and CCDEFEX definitions will be required. For best practice the requirement should be for every control hosted, a pair of CCDEF and CCDEFEX definitions is required.

;Used by RadASM 1.2.0.5
CCDEF          STRUCT
    ID         DD ? ; Controls uniqe ID
    lptooltip  DD ? ; Pointer to tooltip text
    hbmp       DD ? ; Handle of bitmap
    lpcaption  DD ? ; Pointer to default caption text
    lpname     DD ? ; Pointer to default id-name text
    lpclass    DD ? ; Pointer to class text
    style      DD ? ; Default style
    exstyle    DD ? ; Default ex-style
    flist1     DD ? ; Property listbox 1
    flist2     DD ? ; Property listbox 2
    disable    DD ? ; Disable controls child windows. 0=No, 1=Use method 1, 2=Use method 2
CCDEF          ENDS
;Used by RadASM 2.1.0.4+
CCDEFEX        STRUCT
    ID         DD ? ; Controls uniqe ID
    lptooltip  DD ? ; Pointer to tooltip text
    hbmp       DD ? ; Handle of bitmap
    lpcaption  DD ? ; Pointer to default caption text
    lpname     DD ? ; Pointer to default id-name text
    lpclass    DD ? ; Pointer to class text
    style      DD ? ; Default style
    exstyle    DD ? ; Default ex-style
    flist1     DD ? ; Property listbox 1
    flist2     DD ? ; Property listbox 2
    flist3     DD ? ; Property listbox 3
    flist4     DD ? ; Property listbox 4
    lpproperty DD ? ; Pointer to properties text to add
    lpmethod   DD ? ; Pointer to property methods
CCDEFEX        ENDS

Each field of the structures as pointed to by a defined .DATA variable should be filled in to help define how the control will work and respond. As example of a control using both structures could be like this:

.CONST
MYCTRLID       EQU 70000

.DATA
szTip          DB 'My New Control',0
szCap          DB 'Some Text to display',0
szName         DB 'IDC_MYCONTROL',0
szClass        DB 'MyControlClass',0
;                                                                                                        NILTWHCBCMMEVCSDAAMWMTLCSTFMCNAW   SFSTFSGIUSOSMHTxxIIBPOTTAWAATWDD
ccdef          CCDEF <MYCTRLID,offset szTip,0,offset szCap,offset szName,offset szClass,STYLE,EXSTYLE,   11111110000110000000000101000000b, 00010000000000011000000000000000b,0>
ccdefex        CCDEFEX <MYCTRLID,offset szTip,0,offset szCap,offset szName,offset szClass,STYLE,EXSTYLE, 11111110000110000000000101000000b, 00010000000000011000000000000000b,0,0,offset szProperty,offset Methods>

CCDEF and CCDEFEX field details

Additional explanation and coverage of each field used in the CCDEF and CCDEFEX structures may help with understanding their purpose - using the example above.

ID (CCDEF/CCDEFEX) - This is a unique identifier for the custom control. Custom controls should use an value above 65535. In the example we are using a constant MYCTRLID with the value of 70000 to store in the CCDEF and CCDEFEX structures using the ccdef and ccdefex variables.

lptooltip (CCDEF/CCDEFEX) - A pointer to a string containing the tooltip to be displayed when the user hovers over the custom control's image button on the toolbox.

hbmp (CCDEF/CCDEFEX) - A handle to a bitmap used for the custom controls image button on the toolbox. Typically the bitmap is stored and compiled as a BITMAP resource in the custom control, and a call to LoadBitmap (Invoke LoadBitmap,hInstance,IDB_BMP) is used inside the GetDef and GetDefEx functions to obtain the handle and store it in the hbmp field before GetDef and GetDefEx return the pointer to the CCDEF / CCDEFEX variable.

lpcaption (CCDEF/CCDEFEX) - A pointer to a string containing the text associated with the control. This text is shown as the Caption property in the properties list of the control when editing the dialog that uses this custom control. Controls will use this text in different ways: as a title, as some text to display etc.

lpname (CCDEF/CCDEFEX) - A pointer to a string containing the constant text name used to associate the controls id with. Not to be confused with the ID field above, the controls id is used in the resource file. The text representing this id can be used in code to interact with the control. This text is shown as the (Name) property in the properties list of the control when editing the dialog that uses this custom control. The text is appended with a numeric for each new control of that type added to a dialog (IDC_MYCONTROL1 etc). Using the menu option Tools->Export IDs Equ this will be exported to a constant equate (IDC_MYCONTROL1 EQU 1001 for example)

lpclass (CCDEF/CCDEFEX) - A pointer to a string containing the class to use when creating the control. The class must be registered before the control can be used by the RadASM IDE or by any program that creates the control either by a call to CreateWindow/CreateWindowEx or by reference to the class in a dialog when it loads its child resources.

style (CCDEF/CCDEFEX) - The default windows style flags used when creating the control, typically these will include WS_VISIBLE and WS_CHILD at least. Any custom flags you have defined with your control can also be included here. Windows reserves the lower 16bit word of dwStyle for use by the user. See Windows Styles for more details.

exstyle (CCDEF/CCDEFEX) - The default windows extended style flags used when creating the control. Typically this will be 0 unless you have a specific requirement. See Extended Windows Styles for more details.

flist1 (CCDEF/CCDEFEX) - A DWORD size bitmask that indicates which properties are shown in the properties list of the control when editing the dialog that uses this custom control. Note: Only some of the properties are general and can be used by the custom control. These properties are marked with *

Bit Property    Use
31  (Name)      *
30  (ID)        *
29  Left        *
28  Top         *
27  Width       *
26  Height      *
25  Caption     *
24  Border      *
23  SysMenu     -
22  MaxButton   -
21  MinButton   -
20  Enabled     *
19  Visible     *
18  Clipping    *
17  ScrollBar   *
16  Default     -
15  Auto        -
14  Alignment   - 
13  Mnemonic    -
12  WordWrap    -
11  MultiLine   -
10  Type        -
09  Locked      -
08  Child       *
07  SizeBorder  -
06  TabStop     *
05  Font        -
04  Menu        -
03  Class       -
02  Notify      -
01  AutoScroll  -
00  WantCr      -

flist2 (CCDEF/CCDEFEX) - A second DWORD size bitmask that indicates which properties are shown in the properties list of the control when editing the dialog that uses this custom control. Note: Only some of the properties are general and can be used by the custom control. These properties are marked with *

Bit Property    Use
31  Sort        -
30  Flat        -
29  (StartID)   -
28  TabIndex    *
27  Format      -
26  SizeGrip    -
25  Group       *
24  Icon        -
23  UseTabs     -
22  StartupPos  -
21  Orientation - 
20  SetBuddy    -
19  MultiSelect -
18  HideSel     -
17  TopMost     -
16  xExStyle    *
15  xStyle      *
14  IntegralHgt -
13  Image       -
12  Buttons     -
11  PopUp       -
10  OwnerDraw   -
09  Transp      -
08  Timer       -
07  AutoPlay    -
06  WeekNum     -
05  AviClip     -
04  AutoSize    -
03  ToolTip     -
02  Wrap        -
01  Divider     -
00  DragDrop    -

disable (CCDEF only) - Disable controls child windows. 0=No, 1=Use method 1, 2=Use method 2

flist3 (CCDEFEX only) - A third DWORD size bitmask that indicates which custom properties are shown in the properties list of the control when editing the dialog that uses this custom control. Custom properties are defined with the use of the lpproperty and lpmethod fields. See below for details.

flist4 (CCDEFEX only) - A fourth DWORD size bitmask that indicates which custom properties are shown in the properties list of the control when editing the dialog that uses this custom control. Custom properties are defined with the use of the lpproperty and lpmethod fields. See below for details.

lpproperty (CCDEFEX only) - A pointer to a string containing a comma seperated list of custom properties to add to the control which will be shown in the properties list when editing the dialog that uses this control. An example of which is:

szProperty              DB 'TextFontType,TextFontSize,Hand,TextAlign',0 

lpmethod (CCDEFEX only) - A pointer to an array containing information relating to each comma seperated property as defined in the lpproperty field. The pointer to the array is defined in the CCDEFEX structure using an offset (for example Offset Methods where Methods is the start of the array and the variable defined in the .DATA section). Each array entry contains two DWORD values. The first DWORD value indicates the type of property: A true/false, or a multiple selection property. The second DWORD value is a pointer to another structure - the structure it points to depends on the type of property (defined in the first DWORD value), either an array of true/false entries or an array pointing to multiple options.

The supported property types are defined as:

.CONST
PROP_STYLETRUEFALSE         EQU 1 ; TRUE/FALSE style
PROP_EXSTYLETRUEFALSE       EQU 2 ; TRUE/FALSE extended style
PROP_STYLEMULTI             EQU 3 ; Mulitple selection 
PROP_STYLETRUEFALSE_DESC    EQU 4 ; TRUE/FALSE style with custom property description (added in v2.2.2.3)
PROP_EXSTYLETRUEFALSE_DESC  EQU 5 ; TRUE/FALSE extended style with custom property description (added in v2.2.2.3)
PROP_STYLEMULTI_DESC        EQU 6 ; Mulitple selection with custom property description (added in v2.2.2.3

PROP_STYLETRUEFALSE example:

.CONST
HAND_POINTER                EQU 80h

.DATA
szProperty                  db "Hand pointer",0

PropertyHand                dd -1 xor HAND_POINTER,0
                            dd -1 xor HAND_POINTER,HAND_POINTER

Methods                     dd PROP_STYLETRUEFALSE,offset PropertyHand 

PROP_STYLETRUEFALSE_DESC example:

.CONST
HAND_POINTER                EQU 80h

.DATA
szProperty                  db "Hand Pointer",0

PropertyHand                dd -1 xor HAND_POINTER,0
                            dd -1 xor HAND_POINTER,HAND_POINTER
                            db "Specifies if the mouse changes to a hand pointer.",0

Methods                     dd PROP_STYLETRUEFALSE_DESC,offset PropertyHand                         

PROP_STYLEMULTI example:

.CONST
ALIGN_LEFT                  EQU 128 ; left aligned text
ALIGN_RIGHT                 EQU 256 ; right aligned text
ALIGN_CENTER                EQU 512 ; center aligned text

.DATA
szProperty                  DB 'TextAlign',0 

PropertyTextAlign           db 'Left,Right,Center',0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_LEFT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_RIGHT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_CENTER
                            dd -1,0
                        
Methods                     dd PROP_STYLEMULTI,offset PropertyTextAlign

PROP_STYLEMULTI_DESC example:

.CONST
ALIGN_LEFT                  EQU 128 ; left aligned text
ALIGN_RIGHT                 EQU 256 ; right aligned text
ALIGN_CENTER                EQU 512 ; center aligned text

.DATA
szProperty                  DB 'TextAlign',0 

PropertyTextAlign           db 'Left,Right,Center',0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_LEFT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_RIGHT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_CENTER
                            dd -1,0
                            db "Specifies the alignment of text displayed in the control",0
                        
Methods                     dd PROP_STYLEMULTI_DESC,offset PropertyTextAlign

A PROP_STYLEMULTI and PROP_STYLETRUEFALSE combined example:

.CONST
HAND_POINTER                EQU 80h
ALIGN_LEFT                  EQU 128 ; left aligned text
ALIGN_RIGHT                 EQU 256 ; right aligned text
ALIGN_CENTER                EQU 512 ; center aligned text

.DATA
szProperty                  DB 'TextAlign,Hand Pointer',0 

PropertyTextAlign           db 'Left,Right,Center',0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_LEFT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_RIGHT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_CENTER
                            dd -1,0

PropertyHand                dd -1 xor HAND_POINTER,0
                            dd -1 xor HAND_POINTER,HAND_POINTER
                            
Methods                     dd PROP_STYLEMULTI_DESC,offset PropertyTextAlign
                            dd PROP_STYLETRUEFALSE_DESC,offset PropertyHand 

A PROP_STYLEMULTI_DESC and PROP_STYLETRUEFALSE_DESC combined example:

.CONST
HAND_POINTER                EQU 80h
ALIGN_LEFT                  EQU 128 ; left aligned text
ALIGN_RIGHT                 EQU 256 ; right aligned text
ALIGN_CENTER                EQU 512 ; center aligned text

.DATA
szProperty                  DB 'TextAlign,Hand Pointer',0 

PropertyTextAlign           db 'Left,Right,Center',0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_LEFT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_RIGHT
                            dd -1,0
                            dd -1 xor (ALIGN_LEFT or ALIGN_RIGHT or ALIGN_CENTER),ALIGN_CENTER
                            dd -1,0
                            db "Specifies the alignment of text displayed in the control",0

PropertyHand                dd -1 xor HAND_POINTER,0
                            dd -1 xor HAND_POINTER,HAND_POINTER
                            db "Specifies if the mouse changes to a hand pointer.",0
                            
Methods                     dd PROP_STYLEMULTI_DESC,offset PropertyTextAlign
                            dd PROP_STYLETRUEFALSE_DESC,offset PropertyHand