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.
HANDLE latitudeWriteOutHandle = NULL;
HANDLE latitudeReadOutHandle = NULL;
SECURITY_ATTRIBUTES latitudeSecurityAttributes;
latitudeSecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
latitudeSecurityAttributes.bInheritHandle = TRUE;
latitudeSecurityAttributes.lpSecurityDescriptor = NULL;
if (CreatePipe(&latitudeReadOutHandle, &latitudeWriteOutHandle, &latitudeSecurityAttributes, 0))
{
SetHandleInformation(latitudeReadOutHandle, HANDLE_FLAG_INHERIT, 0);
// ^ - no link needed here
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;
latitudeStartUpInfo.hStdError = latitudeWriteOutHandle;
latitudeStartUpInfo.dwFlags |= STARTF_USESTDHANDLES;
if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &latitudeStartUpInfo, &latitudeProcessInformation))
{
CloseHandle(latitudeProcessInformation.hThread);
CloseHandle(latitudeProcessInformation.hProcess);
CloseHandle(latitudeWriteOutHandle);
char latitudeBuffer[COORDINATES_BUFFER_SIZE];
DWORD dwRead;
if (ReadFile(latitudeReadOutHandle, latitudeBuffer, COORDINATES_BUFFER_SIZE, &dwRead, NULL)) {
// ^ - no link needed here too
printf("%s\n", latitudeBuffer);
}
}
}
Also for the buffer you need to use char
instead of wchar_t
.