I'm writing an application to obtain Geolocation on C.
To get the coordinates, I decided to use Popen with PowerShell and this is the code I wrote:
BOOL getLatitude(wchar_t* latitudeBuffer)
{
enableLocation();
FILE* latitudePipe;
if (latitudePipe = _wpopen(L"powershell -c \"Add-Type -AssemblyName System.Device; $GeoCoordinateWatcher = New-Object System.Device.Location.GeoCoordinateWatcher; $GeoCoordinateWatcher.Start(); Start-Sleep -Milliseconds 2500; $GeoCoordinateWatcher.Position.Location.Latitude 2>&1\"", L"r"))
{
wchar_t* latitudeResult = fgetws(latitudeBuffer, COORDINATES_BUFFER_SIZE, latitudePipe);
_pclose(latitudePipe);
if (latitudeResult)
{
if ('0' <= latitudeBuffer[0] && latitudeBuffer[0] <= '9')
{
latitudeBuffer[COORDINATES_SIZE] = '\0';
wchar_t* latitudePoint = wcschr(latitudeBuffer, L'.');
if (latitudePoint != NULL) *latitudePoint = '-';
return TRUE;
}
}
}
wcsncpy_s(latitudeBuffer, COORDINATES_BUFFER_SIZE, L"NULL", COORDINATES_BUFFER_SIZE);
return FALSE;
}
It works, but I encountered a problem that when Popen is used, the terminal opens for a few seconds. And I need everything to happen in the background.
Then I decided to use CreatePipe and CreateProcess, and then read the output using ReadFile, but it did not put the result in the buffer and ended up in an infinite loop. Here's the code:
#define COORDINATES_BUFFER_SIZE 4096
void getLat(wchar_t* latitudeBuffer)
{
enableLocation();
HANDLE latitudeWriteOutHandle = NULL;
HANDLE latitudeReadOutHandle = NULL;
SECURITY_ATTRIBUTES latitudeSecurityAttributes;
latitudeSecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
latitudeSecurityAttributes.bInheritHandle = TRUE;
latitudeSecurityAttributes.lpSecurityDescriptor = NULL;
CreatePipe(&latitudeReadOutHandle, &latitudeWriteOutHandle, &latitudeSecurityAttributes, 0);
SetHandleInformation(&latitudeReadOutHandle, HANDLE_FLAG_INHERIT, 0);
wchar_t cmd[] = L"powershell.exe -c \"Add-Type -AssemblyName System.Device; $GeoCoordinateWatcher = New-Object System.Device.Location.GeoCoordinateWatcher; $GeoCoordinateWatcher.Start(); Start-Sleep -Milliseconds 2500; $GeoCoordinateWatcher.Position.Location.Latitude 2>&1\"";
STARTUPINFO latitudeStartUpInfo;
PROCESS_INFORMATION latitudeProcessInformation;
ZeroMemory(&latitudeStartUpInfo, sizeof(STARTUPINFO));
ZeroMemory(&latitudeProcessInformation, sizeof(PROCESS_INFORMATION));
latitudeStartUpInfo.cb = sizeof(STARTUPINFO);
latitudeStartUpInfo.hStdOutput = latitudeWriteOutHandle; // edited
latitudeStartUpInfo.hStdError = latitudeWriteReadOutHandle; // edited
latitudeStartUpInfo.dwFlags |= STARTF_USESTDHANDLES;
if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &latitudeStartUpInfo, &latitudeProcessInformation))
{
CloseHandle(latitudeProcessInformation.hThread);
CloseHandle(latitudeProcessInformation.hProcess);
CloseHandle(latitudeWriteOutHandle);
DWORD dwRead;
while (TRUE) if (ReadFile(latitudeReadOutHandle, latitudeBuffer, COORDINATES_BUFFER_SIZE, &dwRead, NULL)) break;
CloseHandle(latitudeReadOutHandle);
wprintf(L"%s\n", latitudeBuffer);
}
}
What am I doing wrong?
P.S. To read the coordinate, one iteration of ReadFile is enough for me.
hProcessis late, after theReadFileis done. You may also want to wait for the process to finish (WaitForSingleObject) after the read.CreatePipe()is successful, but more importantly you are not breaking the reading loop ifReadFile()fails. "To read the coordinate, one iteration of ReadFile is enough for me" - then there is no point in using a loop at all. Ether you get the data or you don't. That said, why are you not simply using theGeoLocationobject directly? You shouldn't need to shell out to PowerShell if the object is accessible to native languages via WinRT or COM.GeoLocationin C?