16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
DimmyTypeAsDType
DimAsIntegeri
'Createenoughspaceforelements
myType.darray=Callocate(5,Sizeof(pt))
'Loaddataintoarray
Fori=0To4
myType.darray[i].row=Int(Rnd*10)+1
myType.darray[i].col=Int(Rnd*10)+1
Next
'Printdata
Fori=0To4
LocatemyType.darray[i].row,myType.darray[i].col
Print"X"
Next
'Freeallocatedspace
DeallocatemyType.darray
Sleep
End
Listing 10.6: dynatype.bas
Analysis:
Lines 4 through 7 define a type that will be used in the dynamic array. 
The program will use the row and column to print a character to the screen. Lines 11 
through 13 define the base type. Notice that darray is dimensioned as a pointer to the 
type pt. If you needed an array of integers, you would use As Integer Ptr. The methods 
are the same whether using an intrinsic data type, or another type as illustrated here. 
Line 20 allocates memory for 5 array elements. Since the program is creating an array of 
types, the second parameter to Callocate is the size of the type, pt. For an integer array it 
would be Sizeof(Integer). Lines 23 through 26 initialize the type array with a random 
row and column which will be used within the print code that follows. The access syntax 
in lines 24 and 25 follow what you have already seen; the dot notation is used to access 
the base type field darray, which is then accessed using the pointer indexing method, 
since the program is using a typed pointer. The dot notation is then used to access the 
individual fields of the array type. The syntax is the same as that shown with the type 
memory array, except here you have one additional level of indirection because the array 
is contained within a type.
Lines 29 through 32 use the row and column fields to print an X to the screen. 
Again you can see that the dot notation and pointer index methods are used to access 
the fields within the type. Line 35 frees the memory allocated and the program is closed 
in the usual way.
131
Pdf passwords - C# PDF Password Library: add, remove, edit PDF file password in C#.net, ASP.NET, MVC, WinForms, WPF
Help to Improve the Security of Your PDF Document by Setting Password
pdf password security; password on pdf
Pdf passwords - VB.NET PDF Password Library: add, remove, edit PDF file password in vb.net, ASP.NET, MVC, WinForms, WPF
Help to Improve the Security of Your PDF Document by Setting Password
convert password protected pdf to word online; password pdf files
When you run the program you should see something similar to the following 
output.
X
X
X
X
X
Output 10.6: Output of dynatype.bas
The location of the X's will vary since the rows and columns are generated 
randomly, but since Randomize is not being used, you should the same layout between 
runs.
The two previous programs are quite similar in format. The differences are the 
levels of indirection being used. In the memory array program, the type itself was being 
used as the array element, so the pointer index was used at the top level, with the dot 
notation used to access the field data. In this program, the memory array is embedded 
within the type, so you use the standard dot notation to access the base type field, 
darray, and then use the pointer index method on the field to select the array element. 
Since the array element is a type, you use the dot notation to access the array element 
field, just as you would as if it were a simple type variable.
You could of course create a memory array that contained a memory array. In this 
case, you would use the pointer index method to select the base type element, and then 
the dot notation to select the memory array field, then a pointer index to access the 
element within the embedded array, and finally the dot notation to select the array 
element field. It sounds complicated, but is actually easier to implement than it is to 
explain. The following program modifies the previous program to illustrate this concept.
1
2
3
4
5
6
7
8
9
10
11
12
OptionExplicit
'Thiswillbetheembeddedtype
Typept
rowAsInteger
colAsInteger
EndType
'Thebasetype:
'darraywillcontainarraydata
TypeDType
darrayAsptPtr
132
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
EndType
'Createapointertobasetype
DimmyTypeAsDTypePtr
DimAsIntegeri,j
'Setuprandomnumbergenerator
RandomizeTimer
'Createenoughspacefor3basetypeelements
myType=Callocate(3,Sizeof(Dtype))
'Createspacefor3ptelementswithinbasetype
Fori=0To2
myType[i].darray=Callocate(3,Sizeof(pt))
Next
'Loaddatawithinthetypearrays
Fori=0To2
Forj=0To2
myType[i].darray[j].row=Int(Rnd*10)+1
myType[i].darray[j].col=Int(Rnd*10)+1
Next
Next
'Printdata
Fori=0To2
Forj=0To2
LocatemyType[i].darray[j].row,myType[i].darray[j].col
Print"X"
Next
Next
'Freeembeddedtypearray
Fori=0To2
DeallocatemyType[i].darray
Next
'Freebasetypearray
DeallocatemyType
Sleep
End
Listing 10.7: dyna-type2.bas
Analysis:
Line 4 through 7 define the type that that will be an array within the base 
type. Lines 11 through 13 define the base type. Darray is dimensioned as a pointer to the 
133
type pt since this will be a memory array with the base type. Line 16 defines a pointer to 
the base type, Dtype, since the base type will also be a memory array. Line 17 defines 
two working variables, i and j, which will be used in the For-Next loops to create and load 
data within the types. Line 20 initializes the random number generator. 
Line 23 creates a three-element memory using the base type. Lines 25 through 27 
then create a three-element memory array using the subtype, pt, for each base type 
element. Notice that the base type, myType is indexed using the pointer index method 
since it is a pointer, and each darray element is initialized using Callocate, since darray is 
also a pointer. Lines 30 through 35 load data into the memory array elements row and 
column. The outer For loop indexes the base type pointer, while the inner loop indexes 
the darray type pointer. Since darray is an element of myType, darray is selected using 
the dot notation, and since row and col are elements of daray, these are selected using 
the dot notation.
Lines 38 through 43 use the same logic to print the X's on the screen. The outer 
loop selects the base type pointer, while the inner loop selects the embedded pointer. 
The row and col elements of darray are used in the Locate statement to move the cursor 
to the position described by the row and col variables, and an X is printed to the screen.
Lines 46 through 48 deallocate the darray memory array. The order of deallocation 
is important here. You must deallocate the embedded array first, before you deallocate 
the base type array. If you deallocate the base type array without deallocating the 
embedded array, the embedded array elements will remain in memory causing a 
memory leak. The rule of thumb here is to deallocate the inner most pointer elements 
first, and then work out toward the base pointer element. Line 50 deallocates the base 
type elements, only after the darray elements have been deallocated. The program is 
then closed in the usual way.
When you run the program you should see something similar to the following 
output. There should be nine X's, however since the random number generator is working 
within a 10 by 10 space, it is possible two X's may occupy the same row and column, so 
you may not see all nine X's.
XX
XX
X
X
XX
X
Output 10.7: Output of dyna-type2.bas
134
While this may seem confusing at first, if you look at the code you will see a 
recurring pattern. The pointer elements are selected using the pointer index method, 
followed by the dot notation to select the individual type elements. You start with the 
base type, in this case myType, index the pointer, and then select the elements using the 
dot notation, in this case darray. Since darray is a pointer, it is selected using a pointer 
index, followed by the dot notation to select the row and col elements. The pattern, 
pointer index, dot notation, pointer index, dot notation would be used for as many levels 
as needed to resolve a individual element within the memory array.
The following diagram shows the memory layout of the program.
MyType[0]­>.darray[0]­>.row,.col
.darray[1]­>.row,.col
.darray[2]­>.row,.col
MyType[1]­>.darray[0]­>.row,.col
.darray[1]­>.row,.col
.darray[2]­>.row,.col
MyType[2]­>.darray[0]­>.row,.col
.darray[1]­>.row,.col
.darray[2]­>.row,.col
You can see the pattern reflected in the diagram. If row were a type pointer, then 
you would just repeat the pattern of index, dot notation on row to resolve the next level 
of elements. This type of data structure gives you a lot of flexibility in your programming. 
There is no need to have three darray elements for each base element; myType[0] may 
point to 4 elements and myType[2] may point to 1 element. You would need to add an 
additional field in myType to indicate how many darray elements were each myType 
element, but that is a minor adjustment and easily programmed. What this concept gives 
you is tight control over your data structures, efficient use of memory and at a relatively 
low cost in code.
Function Pointers in Types
Once you have created a type definition, you will usually need to create one or 
more subroutines or functions that act on that data. By using function pointers, you can 
group the code that acts on this data right along with the data itself. This gives you a 
powerful capability to organize your data into code objects that operate as a single unit. 
This is one of the ideas behind OOP, or object oriented programming; encapsulating data 
and the methods (subroutines and functions) that operate on that data into a single 
entity. While FreeBasic doesn't yet support object oriented programming, you can derive 
some of the benefits of OOP by using functions pointers along with data when you create 
your type definitions.
You define a function (or subroutine) pointer by declaring a prototype function 
declaration with the type element name. The following code snippet shows a typical 
declaration.
TypemyObject
arg1AsInteger
arg2AsInteger
retAsInteger
135
myFuncAsFunction(arg1AsInteger,arg2AsInteger)AsInteger
EndType
DeclareFunctiontypeFunc(arg1AsInteger,arg2AsInteger)AsInteger
...
DimObjasmyObject
Obj.myFunc=@typeFunc
...
FunctiontypeFunc(arg1AsInteger,arg2AsInteger)AsInteger
...
EndFunction
The type definition is defined using data in the normal manner, along with a field, 
myFunc, that is defined As Function. When a field is defined As Function or As Sub, this 
creates a pointer to the function or subroutine. Notice that the type definition of myFunc 
doesn't include a function, but does include the parameter and return types. Since this is 
a pointer field, the name isn't required, but the parameters and return type in the 
prototype declaration, must match the actual function in order for the compiler to do type 
checking on the pointer field. 
The Declare statement following the type is needed as a forward reference so that 
the compiler knows that a function is defined somewhere in the code. If you left out the 
declaration, you would get a variable not declared error when trying the to compile the 
code. You create an instance of the type using the Dim statement, just as you have seen 
in the other examples. Since myFunc is a pointer, you can't use it until you initialize the 
pointer and you do this by using the Addressof operator on the real function's name. This 
will store the address of the function in myFunc, which is used when calling the function. 
The real function must be coded of course, so that you actually have some code to call 
when using the function pointer.
The following program illustrates creating and using a function pointer in a type 
def.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OptionExplicit
'Createatypedefinitionthathasdataandfunctionptr
TypemyObject
arg1AsInteger
arg2AsInteger
retAsInteger
myFuncAsFunction(arg1AsInteger,arg2AsInteger)AsInteger
EndType
'Needtodeclarefunctionforforwardreference
DeclareFunctiontypeFunc(arg1AsInteger,arg2AsInteger)AsInteger
'Createatypevariable
DimObjAsmyObject
'Settheaddressofthefunction
Obj.myFunc=@typeFunc
136
17
18
19
20
21
22
23
24
25
26
27
28
29
'Setthedataelements
Obj.arg1=1
Obj.arg2=5
'Callthefunction
Obj.ret=Obj.myFunc(obj.arg1,Obj.arg2)
'Showresult
Print"Funcreturnis";Obj.ret
Sleep
End
FunctiontypeFunc(arg1AsInteger,arg2AsInteger)AsInteger
Returnarg1+arg2
EndFunction
Listing 10.8: type-func.bas
Analysis:
Lines 4 through 9 define a type with both integer data fields and a 
function pointer field. MyFunc is defined As Function along with the function prototype. 
This sets up myFunc as a function pointer. The Declaration statement in line 12 is used as 
a forward reference to the actual function code. If you did not supply the declaration, you 
would get a variable not found error on line 16. Line 14  creates a variable of the type 
and line 16 uses the Addressof operator to initialize the function pointer to the address of 
typeFunc, the actual function. Lines 18 and 19 initialize the data fields, arg1 and arg2. 
Line 21 actually calls the function with the proper arguments. Notice that the dot notation 
is used in calling the function, myFunc as well as passing the data to the function. Obj.ret 
olds the functions return value.
The program is closed using the Sleep and End commands, followed by the 
function definition. Whenever you create a function pointer, you must have some 
corresponding function code in order to pass the address of that code to the function 
pointer.
When you run the program, you should see the following output.
Funcreturnis6
Output 10.8: Output of type-func.bas
As you can see, function pointers are quite simple to define and use. Not only is 
your data encapsulated within a single code object, the methods that act on that data are 
also contained within that same object, giving you a powerful way to organize your data 
structures. The example program is quite simple of course, but you can use this concept 
to reduce the complexity of your code. Suppose you are writing a game and the enemy 
units have been defined using a type definition. By also including the subroutines or 
functions that act on that data within the type definition, you have a single code object 
that fully describes an enemy. If you need to make changes to the enemy code, you only 
137
have to update a single code object, rather than a scattered bunch of variables and 
subroutines.
This method also enables you to pass information to functions or subroutines as a 
single unit, by simply declaring a parameter as the type definition, and you have access 
to both the data and methods within the called function. This makes the code much more 
reliable and easier to maintain. It also enables you to generalize the code so that when 
you create these type of objects, they can be used in other programs.
Forward References
There may be a time when you need to create two type definitions that reference 
each other. Since FreeBasic is a single pass compiler, this poses a problem since the 
compiler will encounter a reference to a type that hasn't been defined yet. The solution is 
to create a forward reference of the second type. You do this by using the Type-As 
keywords, without the End Type.  For example, suppose you have two types Type1 and 
Type2. Type1 references Type2 and Type2 references Type1. It doesn't matter what order 
you define the types, you will generate an error in the compiler, because each type has a 
reference that hasn't been defined yet. In order for the compiler to compile successfully 
you need to create a forward reference to the second type, and then use that reference 
in defining the first type. The following code snippet illustrates this concept.
'Forwardreference
TypeFTasType2
TypeType1

fTypeasFT
EndType
TypeType2

fTypeasType2
EndType
The code TypeFTasType2 creates the forward reference that is in turn used in 
the Type1 definition to refer to Type2, fTypeasFT. FT and Type2 are actually the same 
thing, FT is just an alias for the Type2 definition. Whenever you need to have one or mote 
type definitions refer to each other, you will need to create forward declarations for the 
the types that have not been defined when referenced.
Bit Fields
There is yet another data type that can be used in type definitions, the bit field. Bit 
fields are defined as variable_name: bits As DataType. The variable name must be 
followed with a colon and the number of bits, followed by the data type. Only integer 
data types are allowed within a bit field. Bit fields are useful when you need to keep track 
of boolean type information, such as if a pixel is on or off. The following program 
illustrates using bit fields within a type definition.
1
2
OptionExplicit
138
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TypeBitType
b1:1AsInteger
b2:4AsInteger
EndType
DimmyBitTypeAsBitType
myBitType.b1=1
myBitType.b2=1101
Print"Bitfield1:";myBitType.b1
Print"Bitfield2:";myBitType.b2
Sleep
End
Listing 10.9: bitfield.bas
Analysis:
Lines 3 through 6 define a type with two bit fields. B1 is defined as 1 bit, 
and b2 is defined as 4 bits. Line 8 creates a variable of the type definition. Line 10 sets 
b1 to 1. Since b1 is defined a 1 bit, the only valid values are 0 or 1. Line 11 sets b2 to 
1101. Here there are four bits so you can have a range of 0000 to 1111. Lines 13 and 14 
print out the values of the bits. The program is closed in the usual way.
When you run the program you should see the following output.
Bitfield1:1
Bitfield2:13
Output 10.9: Output of bitfield.bas
The data type of the bit field determines how many bits you can declare in a bit 
field. Since an integer is 32 bits long, you could declare up to 32 bits in the field. 
However, in most cases you would declare a single bit for each field, and use a number of 
fields to define the bit masking that you wish to use. Using a single bit simplifies the 
coding you need to do to determine if a bit is set or cleared.
The Field Property
When you create a variable of a type definition, the type is padded in memory. The 
padding allows for faster access of the type members since the type fields are aligned on 
a 4 byte or Word boundary. However, this can cause problems when trying to read a type 
record from a file that is not padded. You can use the use field property to change the 
padding of a type definition. The field keyword is used right after the type name and can 
have the values 1, for 1 byte alignment (no padding), 2 for 2 byte alignment and 4 for 4 
byte alignment. To define a type with no padding you would use the following syntax.
139
TypemyTypefield=1

v1AsInteger
v2AsByte
EndType
For 2 byte alignment you would use field = 2. If no field = property is assigned, 
then the padding will be 4 bytes. If you are reading a type definition created by FreeBasic 
using the default alignment, then you do not need to use the field property.
If you reading a Quick Basic type record, then you will need to use field = 1, as QB used 
byte alignment by default.
Type Initialization
You can initialize a type definition when you dimension the type just as you can 
any of the intrinsic variables. The following code snippet illustrates the syntax.
TypeaType

aAsInteger

bAsByte

cAsString
EndType
DimmyTypeAsaType=>(12345,12,"Hello")
In the Dim statement, the arrow operator is used to signal the compiler that you 
are initializing the type variable. The type element values must be enclosed in 
parenthesis, and separated by commas. The order of the value list corresponds to the 
order of the type elements, where a will be set to 12345, b to 12 and c to “Hello”. The 
following short program initializes a type using this syntax.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OptionExplicit
'Createatypedef
TypeaType
aAsInteger
bAsByte
cAsString
EndType
'Createandinitthetype
DimmyTypeAsaType=>(12345,12,"Hello")
'Displayvalues
WithmyType
140
Documents you may be interested
Documents you may be interested