Examples

Introduction Example

Example for a simple C function that adds three different parameters and a returns the sum value. The Igor code assumes that a libHandle from a loaded library with FCALL_LoadLibrary was set. First a reusable JSON object for the input parameters of AddValue is created with the utility function FCALL_SetupParameterIn. As the parameter types of the C function stay constant this has to be done only once.

For a function call only the values of the parameters have to be set. When done the JSON object is converted to its string form and used with FCALL_CallFunction.

After the call finished the JSONXOP can be used again for easy parsing of the output.

C Function Declaration
int AddValues(int a, short b, char c);
Setup and call code
// setup once
variable jsonID = FCALL_SetupParameterIn("INT32;INT32;INT16;INT8")

string parameterOut
// for each call set input values, we set here a=1, b=2 and c=3.
JSONXOP_AddValue/O/I=1 jsonID, "/Parameter/0/value"
JSONXOP_AddValue/O/I=2 jsonID, "/Parameter/1/value"
JSONXOP_AddValue/O/I=3 jsonID, "/Parameter/2/value"
// Retrieve json in string form in S_Value
JSONXOP_Dump jsonID
// issue function call
FCALL_CallFunction libHandle, "AddValues", S_Value, parameterOut

// Retrieve result
variable jsonIDOut
JSONXOP_Parse parameterOut; AbortOnRTE
jsonIDOut = V_Value
JSONXOP_GetValue/V jsonIDOut, "/result/value"; AbortOnRTE
printf "a + b + c = %d\r", V_Value
JSONXOP_Release jsonIDOut

PrintFreeDiskSpace

The first real world example shows the usage of the GetDiskFreeSpaceExA function of kernel32.dll that is part of the Windows operating system. At first code block the declaration is shown as present in fileapi.h that is part of the Windows SDK. The second code block shows how the CallFunction XOP is used to retrieve the free disk space. In this example the setup of the JSON object used for input is shown in detail. The function FCALL_GetParameterInJSON creates a skeleton JSON object for four (yet) empty input parameters. Then each type is set with an own call of JSONXOP_AddValue. In the next step all values for the parameters are set. Notably the latter three input parameters are pointers to 64 bit integers where data is returned. For these three single element UINT64 waves are created. The last three parameters are set with type WAVEREF and the path to the waves are set as value.

After the JSON object is fully setup it is dumped to its string form and GetDiskFreeSpaceExA is called. When FCALL_CallFunction returns the output is checked if an error was encountered. If everything went well the GetDiskFreeSpaceExA wrote the returned values directly into the 64 bit integer waves.

C Function Declaration
BOOL GetDiskFreeSpaceExA(
  LPCSTR          lpDirectoryName,
  PULARGE_INTEGER lpFreeBytesAvailableToCaller,
  PULARGE_INTEGER lpTotalNumberOfBytes,
  PULARGE_INTEGER lpTotalNumberOfFreeBytes
);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3		// Use modern global access method and strict wave access.

#include "FCALL_functions"

// The function GetDiskFreeSpaceExA is exported by kernel32.dll and declared in Fileapi.h
// See also https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskfreespaceexa
//
//BOOL GetDiskFreeSpaceExA(
//  LPCSTR          lpDirectoryName,
//  PULARGE_INTEGER lpFreeBytesAvailableToCaller,
//  PULARGE_INTEGER lpTotalNumberOfBytes,
//  PULARGE_INTEGER lpTotalNumberOfFreeBytes
//);
//
// For the parameters we use the following types: STRING, WAVEREF, WAVEREF, WAVEREF
// The waves have one element of type UINT64, that corresponds to ULARGE_INTEGER

static Constant MEGABYTE = 1048576

Function PrintFreeDiskSpace()

	string libHandle
	string sysRoot, dllPath, functionName
	string parameterIn
	string parameterOut = ""
	string errorMsg
	variable errorCode, returnCode
	variable jsonID
	string diskPath = "C:\\"

	sysRoot = GetEnvironmentVariable("SystemRoot")
	dllPath = sysRoot + "\\System32\\kernel32.dll"
	functionName = "GetDiskFreeSpaceExA"

	try
		jsonID = FCALL_GetParameterInJSON(paramCnt = 4)

		// Set result type and parameter types
		JSONXOP_AddValue/T="UINT8" jsonID, "/result/type"; AbortOnRTE
		JSONXOP_AddValue/T="STRING" jsonID, "/Parameter/0/type"; AbortOnRTE
		JSONXOP_AddValue/T="WAVEREF" jsonID, "/Parameter/1/type"; AbortOnRTE
		JSONXOP_AddValue/T="WAVEREF" jsonID, "/Parameter/2/type"; AbortOnRTE
		JSONXOP_AddValue/T="WAVEREF" jsonID, "/Parameter/3/type"; AbortOnRTE
		// Set parameter values
		Make/O/N=1/L/U param1, param2, param3
		JSONXOP_AddValue/T=diskPath jsonID, "/Parameter/0/value"; AbortOnRTE
		JSONXOP_AddValue/T=GetWavesDataFolder(param1, 2) jsonID, "/Parameter/1/value"; AbortOnRTE
		JSONXOP_AddValue/T=GetWavesDataFolder(param2, 2) jsonID, "/Parameter/2/value"; AbortOnRTE
		JSONXOP_AddValue/T=GetWavesDataFolder(param3, 2) jsonID, "/Parameter/3/value"; AbortOnRTE

		JSONXOP_Dump jsonID; AbortOnRTE
		parameterIn = S_Value
	catch
		errorMsg = getRTErrMessage()
		errorCode = getRTError(1)
		printf "Building parameterIn failed with code %d : %s\r", errorCode, errorMsg
	endtry
	JSONXOP_Release jsonID

	FCALL_LoadLibrary dllPath, libHandle; AbortOnRTE

	try
		FCALL_CallFunction libHandle, functionName, parameterIn, parameterOut; AbortOnRTE
	catch
		errorMsg = getRTErrMessage()
		errorCode = getRTError(1)
		printf "CallFunction failed with code %d : %s\r", errorCode, errorMsg
	endtry
	FCALL_FreeLibrary libHandle

	errorCode = FCALL_GetCallError(parameterOut, errorMsg)
	if(errorCode)
		printf "CallFunction returned error %d : %s\r", errorCode, errorMsg
		return NaN
	endif

	JSONXOP_Parse parameterOut; AbortOnRTE
	jsonID = V_Value
	JSONXOP_GetValue/V jsonID, "/result/value"; AbortOnRTE
	if(V_Value != 0)
		printf "FreeBytesAvailableToCaller : %.1f MB\r", param1[0] / MEGABYTE
		printf "TotalNumberOfBytes : %.1f MB\r", param2[0] / MEGABYTE
		printf "TotalNumberOfFreeBytes : %.1f MB\r", param3[0] / MEGABYTE
	else
		printf "%s returned with error.\r", functionName
	endif
	JSONXOP_Release jsonID

End

GetVersion

The kernel32.dll library of Windows also offers a function to retrieve the detailed Windows version. This example print the output of the GetVersion function. The function takes no input parameters and returns a unsigned 32 bit integer result.

C Function Declaration
DWORD GetVersion();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3		// Use modern global access method and strict wave access.

#include "FCALL_functions"

// The function GetVersion is exported by kernel32.dll and declared in sysinfoapi.h
// See also https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversion
//
//DWORD GetVersion();
//
// For the parameters we leave the parameter array empty

Function GetVersion()
	string libHandle
	string sysRoot, dllPath, functionName
	string parameterIn
	string parameterOut = ""
	string errorMsg
	variable errorCode
	variable jsonID
	variable returnValue, majorVersion, minorVersion, build

	sysRoot = GetEnvironmentVariable("SystemRoot")
	dllPath = sysRoot + "\\System32\\kernel32.dll"
	functionName = "GetVersion"

	try
		jsonID = FCALL_GetParameterInJSON()

		// Set result type for DWORD
		JSONXOP_AddValue/T="UINT32" jsonID, "/result/type"; AbortOnRTE

		// The GetVersion function has no input parameter, so we leave Parameter as empty array
		JSONXOP_Dump jsonID; AbortOnRTE
		parameterIn = S_Value
	catch
		errorMsg = getRTErrMessage()
		errorCode = getRTError(1)
		printf "Building parameterIn failed with code %d : %s\r", errorCode, errorMsg
	endtry
	JSONXOP_Release jsonID

	FCALL_LoadLibrary dllPath, libHandle; AbortOnRTE

	try
		FCALL_CallFunction libHandle, functionName, parameterIn, parameterOut; AbortOnRTE
	catch
		errorMsg = getRTErrMessage()
		errorCode = getRTError(1)
		printf "CallFunction failed with code %d : %s\r", errorCode, errorMsg
	endtry
	FCALL_FreeLibrary libHandle

	errorCode = FCALL_GetCallError(parameterOut, errorMsg)
	if(errorCode)
		printf "CallFunction returned error %d : %s\r", errorCode, errorMsg
		return NaN
	endif
	// No Error, we can check results
	JSONXOP_Parse parameterOut; AbortOnRTE
	jsonID = V_Value
	JSONXOP_GetValue/V jsonID, "/result/value"; AbortOnRTE
	returnValue = V_Value
	JSONXOP_Release jsonID

	majorVersion = returnValue & 0xff
	minorVersion = (returnValue & 0xff00) >> 8
	if(returnValue < 0x80000000)
		build = (returnValue & 0xffff0000) >> 16
	endif
	printf "Version is %d.%d (%d)\r", majorVersion, minorVersion, build
End

QueryPerformanceCounter

The QueryPerformanceCounter function of kernel32.dll allows to retrieve the current high-precision performance counter value. In the example an inline array is used to return the value of the first input parameter. When an inline array is used the function parameter is always expected to be a pointer and the parameter type set is the pointers type. Here the parameters type is set to INT64 and the array for the value field contains a single element.

After the call the result is retrieved from the first element of the returned inline array from parameter 0 at “/Parameter/0/value/0”.

C Function Declaration
BOOL QueryPerformanceCounter(
  LARGE_INTEGER *lpPerformanceCount
);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3		// Use modern global access method and strict wave access.

#include "FCALL_functions"

// The function used here is exported by kernel32.dll and declared in profileapi.h
// See also https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter
//
//BOOL QueryPerformanceCounter(
//  LARGE_INTEGER *lpPerformanceCount
//);
//
// For the parameter an inline array is used.
// It is read afterwards with a wave of type INT64, that corresponds to LARGE_INTEGER

Function QueryPerformanceCounter()

	string libHandle
	string sysRoot, dllPath, functionName
	string parameterIn
	string parameterOut = ""
	string errorMsg
	variable errorCode, returnCode
	variable jsonID

	sysRoot = GetEnvironmentVariable("SystemRoot")
	dllPath = sysRoot + "\\System32\\kernel32.dll"
	functionName = "QueryPerformanceCounter"

	try
		jsonID = FCALL_GetParameterInJSON(paramCnt = 1)

		// Set result type and parameter type
		JSONXOP_AddValue/T="UINT8" jsonID, "/result/type"; AbortOnRTE
		JSONXOP_AddValue/T="INT64" jsonID, "/Parameter/0/type"; AbortOnRTE
		// Set as parameter value an inline array with one element
		JSONXOP_AddTree/T=(JSON_ARRAY) jsonID, "/Parameter/0/value"; AbortOnRTE
		JSONXOP_AddValue/I=0 jsonID, "/Parameter/0/value"; AbortOnRTE

		JSONXOP_Dump jsonID; AbortOnRTE
		parameterIn = S_Value
	catch
		errorMsg = getRTErrMessage()
		errorCode = getRTError(1)
		printf "Building parameterIn failed with code %d : %s\r", errorCode, errorMsg
	endtry
	JSONXOP_Release jsonID

	FCALL_LoadLibrary dllPath, libHandle; AbortOnRTE

	try
		FCALL_CallFunction libHandle, functionName, parameterIn, parameterOut; AbortOnRTE
	catch
		errorMsg = getRTErrMessage()
		errorCode = getRTError(1)
		printf "CallFunction failed with code %d : %s\r", errorCode, errorMsg
	endtry
	FCALL_FreeLibrary libHandle

	errorCode = FCALL_GetCallError(parameterOut, errorMsg)
	if(errorCode)
		printf "CallFunction returned error %d : %s\r", errorCode, errorMsg
		return NaN
	endif

	// We don't have to check the returned BOOL as:
	// quote: "On systems that run Windows XP or later, the function will always succeed and will thus never return zero."
	JSONXOP_Parse parameterOut; AbortOnRTE
	jsonID = V_Value
	Make/FREE/L/N=1 wInt64
	JSONXOP_GetValue/L=wInt64 jsonID, "/Parameter/0/value/0"
	printf "PerformanceCount : %d\r", wInt64[0]
	JSONXOP_Release jsonID
End

Music Player

This example implements a very basic music player in Igor Pro. It uses the 64-bit version of the BASS library. It shows how the functions are setup once at the beginning and how the created JSON objects are reused on each call. The example can be run through the added Music Player menu entry.

Music Player

_images/music_player.png

Monochromator

In this example, an Andor Shamrock monochromator and an Andor Newton detector are controlled within Igor Pro. The live example shows how to set and read-out values from the attached monochromator and camera.

_images/andor-igor.gif

Operating the instruments is under full control of Igor Pro. The debug messages show the return values from function calls to the dll files.

The package requires the AndorSDK and calls functions from the following dlls:

  • C:\Program Files\Andor SOLIS\Drivers\Shamrock64
    • atshamrock.dll
    • ShamrockCIF.dll
  • C:\Program Files\Andor SOLIS\Drivers
    • atmcd64d.dll
_images/andor-igor.png

A spectrum directly generated in Igor Pro, ready for further processing.

It should be visible from this example, that it is possible to control actual scientific hardware with Igor Pro using the CallFunction XOP.