Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

DECLARE enigma with the Boolean type

Status
Not open for further replies.

dkean4

Programmer
Feb 15, 2015
282
US
I purchased a little controller board from Velleman K8055. It is designed to work with a DLL and here is an incomplete list of Declarations written in Visual Basic, to access the board.

Code:
Private Declare Function Version Lib "k8055d.dll" () As Long
Private Declare Function SearchDevices Lib "k8055d.dll" () As Long
Private Declare Function SetCurrentDevice Lib "k8055d.dll" (ByVal CardAddress As Long) As Long
Private Declare Function OpenDevice Lib "k8055d.dll" (ByVal CardAddress As Long) As Long

Private Declare Sub CloseDevice Lib "k8055d.dll" ()
Private Declare Function ReadAnalogChannel Lib "k8055d.dll" (ByVal Channel As Long) As Long
Private Declare Sub ReadAllAnalog Lib "k8055d.dll" (Data1 As Long, Data2 As Long)
Private Declare Sub OutputAnalogChannel Lib "k8055d.dll" (ByVal Channel As Long, ByVal Data As Long)
Private Declare Sub OutputAllAnalog Lib "k8055d.dll" (ByVal Data1 As Long, ByVal Data2 As Long)
Private Declare Sub ClearAnalogChannel Lib "k8055d.dll" (ByVal Channel As Long)
Private Declare Sub SetAllAnalog Lib "k8055d.dll" ()
Private Declare Sub ClearAllAnalog Lib "k8055d.dll" ()
Private Declare Sub SetAnalogChannel Lib "k8055d.dll" (ByVal Channel As Long)
Private Declare Sub WriteAllDigital Lib "k8055d.dll" (ByVal Data As Long)
Private Declare Sub ClearDigitalChannel Lib "k8055d.dll" (ByVal Channel As Long)
Private Declare Sub ClearAllDigital Lib "k8055d.dll" ()
Private Declare Sub SetDigitalChannel Lib "k8055d.dll" (ByVal Channel As Long)
Private Declare Sub SetAllDigital Lib "k8055d.dll" ()
Private Declare Function ReadDigitalChannel Lib "k8055d.dll" (ByVal Channel As Long) As Boolean
Private Declare Function ReadAllDigital Lib "k8055d.dll" () As Long
Private Declare Function ReadCounter Lib "k8055d.dll" (ByVal CounterNr As Long) As Long
Private Declare Sub ResetCounter Lib "k8055d.dll" (ByVal CounterNr As Long)
Private Declare Sub SetCounterDebounceTime Lib "k8055d.dll" (ByVal CounterNr As Long, ByVal DebounceTime As Long)
Private Declare Function SetTimer Lib "user32" ( _
    ByVal HWnd As Long, ByVal nIDEvent As Long, _
    ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" ( _
    ByVal HWnd As Long, ByVal nIDEvent As Long) As Long

I have successfully converted some and I cannot convert others to work properly in VFP. The lines in red are resisting me by not returning values.

Code:
DECLARE Integer OpenDevice IN k8055d.dll Integer CardAddress
DECLARE SetDigitalChannel IN k8055d.dll Integer Channel
[COLOR=#CC0000]DECLARE Integer ReadDigitalChannel IN k8055d.dll integer Channel[/color]
DECLARE ClearDigitalChannel IN k8055d.dll integer Channel
[COLOR=#CC0000]DECLARE Integer [COLOR=#CC0000]ReadAllDigital[/color] IN k8055d.dll[/color][COLOR=#CC0000][/color]
DECLARE CloseDevice IN k8055d.dll
DECLARE ClearAllDigital IN k8055d.dll

The problem appears to be simple. In VB these Declarations are defined as Functions. Dennis however is using the "Integer" type. VFP does not have the Boolean option and after a million tests I was able to get a result for the OpenDevice Declaration to return a 0 to me, which indicates that the device was opened. That works great and reliably. The other Function declarations, however set the return value to Boolean and VFP does not have a Boolean option. What can I do there?

Some of you guys may have lots more experience with DLLs and Declarations than me. Any help is appreciated...



Dennis Kean

Simplicity is the extreme degree of sophistication.
Leonardo da Vinci
 
Using FunctionType Integer for Boolean works for many API functions, even native Windows API functions. No idea.
There are 7 possible function types VFP DECLARE DLL supports, try out each one of them.

Bye, Olaf



 
An integer type should do.

I checked the DLL documentation and found an inconsistency regarding the ReadDigitalChannel function: the example code for the function refers to ReadIOChannel, not to ReadDigitalChannel. Maybe you should double-check the entry name and be sure...
 
Atlopes,

I get
Error said:
Cannot find entry point ReadIOChannel in the DLL.
I do have the latest update of the DLL.

Atlopes, I opened the DLL in a text editor and found these keywords...

Keywords said:
\ K8055D.dll
ClearAllAnalog
ClearAllDigital
ClearAnalogChannel
ClearDigitalChannel
CloseDevice
OpenDevice
OutputAllAnalog
OutputAnalogChannel
ReadAll
ReadAllAnalog
ReadAllDigital
ReadAnalogChannel
ReadCounter
ReadDigitalChannel
ResetCounter
SearchDevices
SetAllAnalog
SetAllDigital
SetAnalogChannel
SetCounterDebounceTime
SetCurrentDevice
SetDigitalChannel
Version
WriteAllDigital


By the way, is there any way I can write some calls using VB and subvert it to VFP to let VB make the calls and pass the returned data to VFP? Maybe someone has already done that. I can't believe that DLLs cannot be fully used by VFP...

Dennis Kean

Simplicity is the extreme degree of sophistication.
Leonardo da Vinci
 
Olaf,

You said:
Olaf said:
Using FunctionType Integer for Boolean works for many API functions, even native Windows API functions. No idea.
There are 7 possible function types VFP DECLARE DLL supports, try out each one of them.

The Function calls have a response to convey back to the caller. Is it possible that VFP has no ability to take full advantage of DLLs??? VFP can Compile DLLS, how do VFP DLLs reply, if that is the case???



Dennis Kean

Simplicity is the extreme degree of sophistication.
Leonardo da Vinci
 
VFP DLLs are never cdecl function libraries, but always only contain COM Servers. DECLARE can declare this (your k8055d.dll), just try out all the possible return types and you will get a return value, 0/1 instead of .T./.F. or any char instead...you will get something you can turn to VFP logical.

Bye, Olaf.
 
Apart from not being able to work with callback functions, which are not involved in this case, I'm not aware of any specific VFP limitation that could prevent the consumption of this library.

So, when you say that ReadDigitalChannel and ReadAllDigital
Dennis said:
are resisting me by not returning values
does it mean that calling those functions will never return, freezing your program, or that they are not returning values you would expect?
 
or that they are not returning values you would expect?

And if that's the case, why not simply trap the returned value in a variable, and use TYPE() or VARTYPE() to determine the data type?

(That said, I think Olaf has already given you the correct answer. VB booleans are just integers, with 0 and 1 corresponding to false and true.)

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
As already said many WinAPI functions are declared to return bool and their description describes the return value as zero or non zero, but most important a number. The classic understanding of bools is 0 and 1 anyway, or 0 and not 0. Often enough -1 is true, as -1 in two's complement means all bits are 1 in whatever width a numeric type has, eg FF byte, FFFF word, so you could also get String CHR(0), CHR(1) or CHR(ff) or ....

For example see
MSDN said:
Return value
Type: BOOL
If the window was brought to the foreground, the return value is nonzero.
If the window was not brought to the foreground, the return value is zero.

Bye, Olaf.
 
I have a little project for one of these boards - written in VFP 9

Would you like a copy to play with?

I don't use it any more, I developed it to make a cooling fan controller for a server farm I used to have in my garage - possibly the most expensive way to make a thermostat I could imagine.


I am presuming you are talking about the USB experimentation board? It uses the same declarations.

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Griff,

Yes, please, I would love to see a properly working way of calling these functions/calls, please!


Thanx in advance, Griff.


Dennis Kean

Simplicity is the extreme degree of sophistication.
Leonardo da Vinci
 
Maybe not all, but enough.

I will make a link available tomorrow.

It's not very 'ala mode'

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Olaf,
Here are the test results for the ReadDigitalChannel call:

tezt_ywtpw0.png


Port #1 is ON (UU)
Port #2 is OFF (UU2)

Here is the picture of the controller with Port #1 LED lit up and the rest all being OFF:

tezt3_tmpdzi.png


It all gives me the .T. result, except OpenDevice(0) and ReadAllDigital

Open device behaves exactly as you have suggested.
0 = Connected
.F. = Not connected

The types are different, but it is still better than nothing.

And here are the results for the call ReadAllDigital:

tezt2_bfqs0q.png


So, I am at an impasse. Nevertheless, you knew the trick about logical and numeric results. I stumbled into that yesterday, but wanted you to know that I did all this already. Hopefully Griff will come through.

Thank you anyway, Olaf... you always get close as possible to the problem.

Dennis Kean

Simplicity is the extreme degree of sophistication.
Leonardo da Vinci
 
Dennis said:
Open device behaves exactly as you have suggested.
0 = Connected
.F. = Not connected

The types are different, but it is still better than nothing.

This seems strange. How do you test if a device is connected or not? By checking the result's data type, and not its value? And, first, how did you manage to get a DECLARE INTEGER to return a Logical result?
 
C'mon, I suggested you vary the function type, not the parameter type. You want to get the boolean result, don't you? What does it help to change the type of the Channel parameter? It is long/integer. You want the boolean to come out, don't you? Vary that part of the declaration. DECLARE INTEGER..., DECLARE LONG..., DECLARE SHORT..., DECLARE SINGLE..., DECLARE DOUBLE..., DECLARE OBJECT...

All your ReadDigitalChannel Declarations were without specifying a result type, so what do you expect? The output of that function is not returned and the .T. simply is the default value VFP returns instead most probably.

See cFunctionType explanation in
Bye, Olaf.
 
In regard of OpenDevice I second atlopes, with DECLARE INTEGER OpenDevice you can only get back ints, not .F., the definition of that function also has a long result type, not a boolean. Reading a german manual this function returns the address (memory address) of the card you open. The cardaddress value you pass in must be between 0 and 3 and is what you set at the card via jumpers SK5 and SK6, so you might simply have this wrong and don't communicate with the card at all by opening or trying to open the wrong cardaddress?

Bye, Olaf.

 
A further point to note: in VFP, functions that do not return a explicit value always return .T. by default. So, if you DECLARE a DLL entry without a return type, whenever you call it you'll always get back a .T.

Code:
CLEAR

? Dummy()

FUNCTION Dummy ()
ENDFUNC

will display .T.
 
Yes, atlopes, not sure if that's the same in DECLARE functions, but it's what Dennis shows and would explain all the .T. results.

More background on DECLARE: With a DECLARE you instanciate a function handler in the VFP object memory, it forwards your calls to the DLL and passes back return values, so you never talk to the DLL directly, you always talk through a VFP runtime internal layer, which also handles memory allocation and deallocation and more. I don't know the exact inner workings, but I know DECLARE doesn't wire a function name with the DLL directly and if you call a function you go directly from your own VFP opcode to the DLL, there is a VFP specific layer in between, eg adding string termination chr(0).

You never get the native VFP .T. or .F. values from any DECLARED function directly, because that's a very specific VFP logical type and has nothing to do with the general or VB or any other languages boolean type you can get back from a DLL. In a DBF VFP really stores the letters "F" and "T", while merely any other language and database stores 0 and 1 or -1 in eg a bit datatype or a byte for todays convenience of addressing memory.

So you only get out something, if you declare a function with a type and if you get out .F. you should look close and see whether that's just the initial or previous value of your variable, unchanged by the function, if the function really just returns void/nothing. But it's likely VFP acts as with the Dummy function atlopes showed, no RETURN statement compares to no FunctionType being declared, so ? prints .T. or variables are set .T. because of standard VFP behaviour in such a case, it can't return nothing. Anyway, BOOLEAN or LOGICAL is not among the functiontypes VFP DECLARE supports, so it's also not foreseen the mentioned VFP layer between you calls and the DLL returns the VFP logical type in any situation aside of no function type declared, so VFP returns default .T., but never .F.

Bye, Olaf.

 
And once more in detail. Your initial thoughts are good:

Code:
Private Declare Function ReadDigitalChannel Lib "k8055d.dll" (ByVal Channel [COLOR=#CC0000]As Long[/color]) [COLOR=#4E9A06]As Boolean[/color]
That VB code likely translates and should work with this VFP declaration you have or had initially:
Code:
DECLARE [COLOR=#4E9A06]Integer[/color] ReadDigitalChannel IN k8055d.dll [COLOR=#CC0000]Integer[/color] Channel
Here I marked in color what corresponds to each other.

As that doesn't work I would initially only vary the output type, not the type of the Channel parameter, anyway, it surely can also be the input parameter getting in wrong and thus leading to wrong output, but you have to declare an output function type to get something anyway. And you might already fail on OpenDevice, indeed. If an Integer does not return anything but 0 as output, this can of course also be explained by the device not being opened and if you run VFP code in parallel to a native testing executable, you might have the device open "exclusive", like with a DBF or better perhaps like a serial COM port is a resource only one process can open at any time. So seeing and comparing is believing, but doing so causes your VFP declared functions to get no access. Many things can still be in your way, more than merely the DECLARation not working out.

If all else fails install the free community edition of visual studio, make yourself a bit comfortable with it and compile a .net assembly DLL with this class:
Code:
public sealed class K8055
    {
        [DllImport("K8055D.DLL")]
        public static extern int OpenDevice(int addr);
        [DllImport("K8055D.DLL")]
        public static extern void CloseDevice();
        [DllImport("K8055D.DLL")]
        public static extern int ReadAnalogChannel(int channel);
        [DllImport("K8055D.DLL")]
        public static extern int ReadAllAnalog(int data1, int data2);
        [DllImport("K8055D.DLL")]
        public static extern void OutputAnalogChannel(int channel, int data);
        [DllImport("K8055D.DLL")]
        public static extern void OutputAllAnalog(int data1, int data2);
        [DllImport("K8055D.DLL")]
        public static extern void ClearAnalogChannel(int channel);
        [DllImport("K8055D.DLL")]
        public static extern void SetAllAnalog();
        [DllImport("K8055D.DLL")]
        public static extern void ClearAllAnalog();
        [DllImport("K8055D.DLL")]
        public static extern void SetAnalogChannel(int channel);
        [DllImport("K8055D.DLL")]
        public static extern void WriteAllDigital(int data);
        [DllImport("K8055D.DLL")]
        public static extern void ClearDigitalChannel(int channel);
        [DllImport("K8055D.DLL")]
        public static extern void ClearAllDigital();
        [DllImport("K8055D.DLL")]
        public static extern void SetDigitalChannel(int channel);
        [DllImport("K8055D.DLL")]
        public static extern void SetAllDigital();
        [DllImport("K8055D.DLL")]
        public static extern bool ReadDigitalChannel(int channel);
        [DllImport("K8055D.DLL")]
        public static extern int ReadAllDigital();
        [DllImport("K8055D.DLL")]
        public static extern int ReadCounter(int nr);
        [DllImport("K8055D.DLL")]
        public static extern void ResetCounter(int nr);
        [DllImport("K8055D.DLL")]
        public static extern void SetCounterDebouncetime(int nr, int debtime);
    }

This then can be used in VFP via dotnetBridge from RickStrahl: - the only bigger downside of this is adding a dependency to a .net runtime version just to have a different intermediate layer between VFP and the DLL.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top