K8061 with c++, mingw compiler

Hello, I have a few K8061 boards and have written several programs in VB using the supplied dll files, no problems what so ever, works perfect!

But now I am trying to write an application in C++ with Eclipse CDT as environment using a mingw compiler…

I still use the K8061.dll and my test code looks like this:

#include <iostream>
#include <windows.h>

using namespace std;

#define NUMBER_OF_RUNS 1
#define LEDS_PER_RUN 3

HINSTANCE dll;
int cardAddress;
typedef int (*OpenDevice)();
typedef void (*CloseDevices)();
typedef void (*SetDigitalChannel)(int, int);
typedef void (*ClearAllDigital)(int);
OpenDevice openDevice;
CloseDevices closeDevices;
SetDigitalChannel setDigitalChannel;
ClearAllDigital clearAllDigital;

void loadDll()
{
	dll = LoadLibrary("K8061.dll");
	if(!dll)
		cardAddress = -3;
	else
	{
		openDevice = (OpenDevice) GetProcAddress(dll, "OpenDevice");
		closeDevices = (CloseDevices) GetProcAddress(dll, "CloseDevices");
		setDigitalChannel = (SetDigitalChannel) GetProcAddress(dll, "SetDigitalChannel");
		clearAllDigital = (ClearAllDigital) GetProcAddress(dll, "ClearAllDigital");
		cardAddress = openDevice();
	}
}

void loopLeds()
{
	for(int i=0 ; i<NUMBER_OF_RUNS ; i++)
	{
		for(int j=0 ; j<LEDS_PER_RUN ; j++)
		{
			setDigitalChannel(cardAddress, j + 1);
			Sleep(200);
		}
		Sleep(1000);
		clearAllDigital(cardAddress);
	}
}

void closeDll()
{
	closeDevices();
	FreeLibrary(dll);
}

int main()
{
	loadDll();
	switch(cardAddress)
	{
	case -3:
		cout << endl << "DLL failed to load." << endl;
		break;
	case -2:
		cout << endl << "No card found." << endl;
		break;
	case -1:
		cout << endl << "All cards opened." << endl;
		break;
	default:
		cout << endl << "Card " << cardAddress << " connected." << endl;
		loopLeds();
		break;
	}
	closeDll();
	return 0;
}

When running this as it is it seems to work, I get console output “Card 0 connected.” and digital outputs 1-3 lights up in order.

When changing define NUMBER_OF_RUNS from 1 to 2, it first seem to work, the console output is still “Card 0 connected.” and the leds light up as before but twice as intended, but this time i also get an access violation error (code 0xc000000005) and application terminates.

And when changing define NUMBER_OF_RUNS to 3 and LEDS_PER_RUN to 8 which should make all digital output leds light up from 1 to 8 three times in a row, the first two runs work OK, but on the third just the first 5 leds light up and then the application justs abort, this time no error message…

Since I have never really programmed in an unmanaged programming language before maybe my program somehow crashes because of bad memory management or maybe the dll is not suited for c++ programming?

Would be really thankful if someone could help me get this board running without problems in c++!

EDIT: I use the dll from the “vista pack” but have also tried original one and mpusbapi.dll.

Regards,

/Simon

Have you tried the K8061_C.DLL ?
This DLL is better for C++ (I think).

Thank you for your reply VEL255,

I had in fact tried with that dll before, but never got it to work so I gave up and tried with the one that at least seemed to work a little…

But since you recommended me to try again I worked a little harder to get it to compile and now it actually compiles and runs with no problems at all! :smiley:

Now I just wish I had asked here earlier and not wasted so many hours on the wrong dll file… :wink:

Thanks again!

/Simon

Nice that you got it working!
Thanks also for the good example code snippet.
Strange that it didn’t work with the other DLL. If I understand right, there is dynamic DLL loading used. It should work with all DLLs…

Edit: I removed this post since it incorrectly said I had problems with the CloseDevices function. I have resolved the problem I thought that I had by just disconnecting the power and USB from the board and reconnecting. I will instead post my program for reference if someone else has the same problems I had to get the board running with mingw c++ compiler:

My main program:
Uses the digital out LED:s to verify that the communication to the board is OK.
(using conio.h and kbhit() is not really recommended, it’s just the easiest way to end a running program with a key hit in a Windows environment)

// K8061Test.cpp

#include <conio.h>
#include <iostream>
#include <windows.h>
#include "K8061_C.h"

using namespace std;

int cardAddress;

void loopLeds()
{
	int index = 1, lastIndex = 2;
	bool increasing = true;
	ClearAllDigital(cardAddress);
	while(!kbhit())
	{
		SetDigitalChannel(cardAddress, index);
		ClearDigitalChannel(cardAddress, lastIndex);
		lastIndex = index;
		if(increasing)
			++index;
		else
			--index;
		if(index == 8)
			increasing = false;
		if(index == 1)
			increasing = true;
		Sleep(100);
	}
}

int main()
{
	cardAddress = OpenDevice();
	cout << endl << "Address: " << cardAddress << endl;
	loopLeds();
	CloseDevices();
	return 0;
}

The K8061_c.h file edited to compile with mingw:

// K8061_c.h
#ifndef K8061_C_H_
#define K8061_C_H_

extern "C"
{
#define FUNCTION __declspec(dllexport)

FUNCTION int __stdcall OpenDevice();
FUNCTION void __stdcall CloseDevices();
FUNCTION int __stdcall ReadAnalogChannel(int CardAddress, int Channel);
FUNCTION bool __stdcall PowerGood(int CardAddress);
FUNCTION bool __stdcall Connected(int CardAddress);
FUNCTION void __stdcall ReadVersion(int CardAddress, long *Buffer);
FUNCTION void __stdcall ReadAllAnalog(int CardAddress, long *Buffer);
FUNCTION void __stdcall OutputAnalogChannel(int CardAddress, int Channel, int Data);
FUNCTION void __stdcall OutputAllAnalog(int CardAddress, long *Buffer);
FUNCTION void __stdcall ClearAnalogChannel(int CardAddress, int Channel);
FUNCTION void __stdcall SetAllAnalog(int CardAddress);
FUNCTION void __stdcall ClearAllAnalog(int CardAddress);
FUNCTION void __stdcall SetAnalogChannel(int CardAddress, int Channel);
FUNCTION void __stdcall OutputAllDigital(int CardAddress, int Data);
FUNCTION void __stdcall ClearDigitalChannel(int CardAddress, int Channel);
FUNCTION void __stdcall ClearAllDigital(int CardAddress);
FUNCTION void __stdcall SetDigitalChannel(int CardAddress, int Channel);
FUNCTION void __stdcall SetAllDigital(int CardAddress);
FUNCTION bool __stdcall ReadDigitalChannel(int CardAddress, int Channel);
FUNCTION int __stdcall ReadAllDigital(int CardAddress);
FUNCTION void __stdcall OutputPWM(int CardAddress, long Data);
FUNCTION void __stdcall Version();
}
#endif

You will also need the K8061_C.lib file and link it manually or adding it to the linked libraries in your IDE.

Last thing: Put K8061_C.DLL in the folder where your exe is compiled.

The K8061_C.lib, K8061_C.DLL and K8061_C.h can be found in the VC6 folder in k8061_vistapack_2007v1.zip which can be downloaded from http://www.vellemanusa.com/us/enu/download/files/

Regards,

/Simon

Remember to always check the calling convention. Most Windows DLL’s use stdcall, but C/C++ might be using the cdecl calling convention by default. This might corrupt the stack and cause strange behavior; like you had where it worked once and then started going wrong (stack starts getting corrupted), ending in an access violation (stack causes the program to jump to protected memory).

If you decide to use dynamic DLL loading with LoadLibrary and GetProcAddress, it is advised to check the return value of these functions to see if they returned without error.

On the side: int and long are usually of the same size in 32-bit C/C++ compilers, so you can use int everywhere instead of long to avoid confusion.

You can probably leave out __declspec(dllexport), since it is only used to export symbols, mostly when you’re compiling a DLL, not when you’re using it.

Have fun!