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.
I finally realized what was wrong in my code. First, I want to thank Ben Voigt for the correct answer. So here is the code that started working for me.
Also for the buffer you need to use
charinstead ofwchar_t.