What we haven't covered so far is some of the tricks and trouble spots you can run into while trying to do this. The first thing you need to know is that sometimes substitutions and slight-of-hand can be used to create additional callable C types. Before we cover that, here is a list of data types and their sizes, in bytes:
C Type |
Length in Bytes |
short |
2 |
int |
4 |
long |
4 |
float |
4 |
double |
8 |
char |
1 |
HSTRING |
4 |
long * |
4 |
double * |
4 |
char * |
4 |
void * |
4 |
PHSTRING |
4 |
NOTE: 1-byte is 8-bits
Size is important because you can often find an ESL type of the same size expected by the C function. This is useful if ESL is simply "passing a value through" to another external call. Lets look at a quick example of this. Say you have a function that returns a pointer to a string (PSTR) and another function that requires a pointer to a string to remove any spaces. Since ESL doesn't need to manipulate the string pointer but only passes it to the another external call, PSTR could be stored in an ESL integer. As mentioned earlier this is possible because both PSTR and an ESL integer are 4-bytes in size. Remember ESL does not view PSTR as a pointer and the integer should not use the reference keyword or try to alter this integer in any way.
Another useful substitution is to use structures and the using clause to pass pointers that aren't supported with the reference keyword. This works because when you pass a structure through an external call, we pass the structure by reference. But this means we are passing a pointer to the structure, which is REALLY a pointer to the first field in the structure. So if you put an ESL string with the string conversion clause as the first, and only field, in a structure; when you pass that structure you are really passing a pointer to a string. Lets look at an example:
If we have a function called MakeUpper in a DLL called string.dll that takes a string pointer we could make the call in ESL like this,
This same approach can be used for string, integer, and float using clauses, which add the following types:
C Type |
associated using clause |
char * |
using string size N, where N includes NULL |
short * |
using integer size 2 |
float * |
using float size 4 |
Another hurdle which you may run into is the use of predefined constants in a function call. Quite often these constants will not be in a decimal format, which is required by ESL. If this is the case you will need to convert the defined format to a decimal format. For example:
should become
The Windows API viewer, provides all the Operating System constants, however, if dealing with a third party DLL, you may well find a search for the constant, using Windows Explorer search facility useful. You will only need to search header files, i.e. those with a file extension of ".h ".
We will now conclude the discussion of unsigned versus signed data types. With signed numbers the first bit is used to mark a number as positive or negative and thus represents a smaller number range then an unsigned number. ESL passes integers as signed numbers to external calls, but remember in most cases it is the size that we really are concerned with, and they are the same for both signed and unsigned numbers. In order to convert unsigned to signed and back you need to be familiar with how signed numbers are represented in binary. Converting a unsigned number to signed uses 2's complement, which says you must inverse all the bits of the unsigned number and add one. Let's look at an example of this:
0000 0000 0000 0001 (unsigned 1 in binary)
by inversing the bits we get:
1111 1111 1111 1110 (1's complement of 1 in binary)
now we need to add 1 to get the 2's complement
1111 1111 1111 1111 (2's complement of 1 or -1 in binary)
We can now represent -1 as an unsigned decimal number
-1 (signed integer)
1111 1111 1111 1111 (binary value from above)
65535 (unsigned integer)
This can get interesting if you want to pass numbers larger then 2^15 from ESL to external calls. Really what you need to do is make the number negative to set the 16th bit and pass the equivalent value. Lets look at examples of doing this:
2147483649 |
decimal |
8 0 0 0 0 0 0 1 |
hex |
1000 0000 0000 0000 0000 0000 0000 0001 |
binary |
1111 1111 1111 1111 1111 1111 1111 1110 |
1's binary |
1111 1111 1111 1111 1111 1111 1111 1111 |
2's binary |
1 7 f f f f f f f |
hex |
-2147483647 |
signed int |
|
|
4294967293 |
decimal |
f f f f f f f d |
hex |
1111 1111 1111 1111 1111 1111 1111 1101 |
binary |
1000 0000 0000 0000 0000 0000 0000 0010 |
1's binary |
1000 0000 0000 0000 0000 0000 0000 0011 |
2's binary |
-3 |
signed int |