Tobii Pro SDK C API
call_eyetracker_manager_windows.c
#include <windows.h>
#include <stdio.h>
#include "Shlwapi.h"
#include "tobii_research.h"
/*
Path to Eye Tracker Manager is
%LocalAppData%\TobiiProEyeTrackerManager\app*\TobiiProEyeTrackerManager.exe
where app* needs to be resolved.
*/
static void GetEyeTrackerManagerPath(char* path, DWORD size) {
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
if (!GetEnvironmentVariable("LocalAppData", path, size)) {
perror("Local App");
exit(EXIT_FAILURE);
}
PathAppend(path, "TobiiProEyeTrackerManager\\app*"); // Adding wildcard since version might vary
// Resolving app* to app-<version>
hFind = FindFirstFile(path, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
perror("FindFirstFile");
exit(EXIT_FAILURE);
}
FindClose(hFind);
PathRemoveFileSpec(path); // Removing app* before adding resolved path
PathAppend(path, FindFileData.cFileName);
PathAppend(path, "TobiiProEyeTrackerManager.exe");
}
static void AddArgsToEyeTrackerManagerCall(char* call, DWORD call_size) {
char* deviceaddress;
TobiiResearchStatus status = tobii_research_get_eyetracker("tobii-ttp://IS404-100107417574", &eyetracker);
if (status != TOBII_RESEARCH_STATUS_OK) {
printf("ERROR: %d when trying to get eyetracker!\n", status);
exit(EXIT_FAILURE);
}
status = tobii_research_get_address(eyetracker, &deviceaddress);
if (status != TOBII_RESEARCH_STATUS_OK) {
printf("ERROR: %d when trying to get address!\n", status);
exit(EXIT_FAILURE);
}
_snprintf(call, call_size,"%s --device-address=%s --mode=%s", call, deviceaddress, "displayarea");
}
static void PrintfLinesStartingWith(HANDLE f, const char* line_start) {
DWORD bytes_read;
#define BUF_SIZE 64
CHAR buf[BUF_SIZE];
BOOL success = FALSE;
BOOL found_matching_line_start = FALSE;
size_t line_start_len = strlen(line_start);
size_t bytes_to_read = line_start_len;
if (line_start_len > BUF_SIZE) {
printf("ERROR: %s longer then BUF_SIZE!\n", line_start);
exit(EXIT_FAILURE);
}
do {
/*
Comparing if begining of stream starts with to line_start,
then reading char by char until newline detected, then comparing with line_start
*/
ZeroMemory(buf, sizeof(buf));
success = ReadFile(f, buf, (DWORD)bytes_to_read, &bytes_read, NULL);
if (bytes_read == 1 && buf[0] == '\n' ) { // End of line found
found_matching_line_start = FALSE;
bytes_to_read = line_start_len;
} else if (bytes_read == line_start_len && !strncmp(buf, line_start, line_start_len)) {
found_matching_line_start = TRUE;
bytes_to_read = 1;
}
if (found_matching_line_start) {
printf("%s", buf);
}
} while (success || bytes_read != 0);
}
/* Based on example https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx */
#pragma comment(lib, "Shlwapi.lib")
int main(/*int argc, char *argv[]*/) {
HANDLE hChildStd_OUT_Rd = NULL;
HANDLE hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0)) {
perror("StdoutRd CreatePipe");
exit(EXIT_FAILURE);
}
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
perror("Stdout SetHandleInformation");
exit(EXIT_FAILURE);
}
// Setting up Eye Tracker Manager call
char ETM_CALL[MAX_PATH];
ZeroMemory(ETM_CALL, sizeof(*ETM_CALL)*MAX_PATH);
GetEyeTrackerManagerPath(ETM_CALL, MAX_PATH);
AddArgsToEyeTrackerManagerCall(ETM_CALL, MAX_PATH);
// Set up members of the PROCESS_INFORMATION structure.
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDOUT and STDERR handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdOutput = hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
if (!CreateProcess(NULL,
ETM_CALL, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo) // receives PROCESS_INFORMATION
) {
perror("Create Process failed!!\n");
exit(EXIT_FAILURE);
}
// Wait until process has exit.
DWORD exitcode;
WaitForSingleObject(piProcInfo.hProcess, INFINITE);
GetExitCodeProcess(piProcInfo.hProcess, &exitcode);
CloseHandle(hChildStd_OUT_Wr);
// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example.
if (exitcode == 0) {
printf("Eye Tracker Manager was called successfully!\n");
} else {
printf("Eye Tracker Manager call returned the error code: %lu\n", exitcode);
// On Windows ETM error messages are logged to stdout
PrintfLinesStartingWith(hChildStd_OUT_Rd, "ETM Error:");
}
CloseHandle(hChildStd_OUT_Rd);
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}