我正在编写一个应用程序来获取 C 上的地理位置。
为了获取坐标,我决定将 Popen 与 PowerShell 结合使用,这是我编写的代码:
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;
}
它可以工作,但是我遇到了一个问题,当使用 Popen 时,终端打开了几秒钟。我需要一切都在后台发生。
然后我决定使用
CreatePipe
和CreateProcess
,然后使用ReadFile
读取输出,但它并没有将结果放入缓冲区中,最终陷入了无限循环。这是代码:
#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);
}
}
我做错了什么?
附注要读取坐标,
ReadFile
的一次迭代对我来说就足够了。
您将管道的错误一端传给了孩子。
latitudeStartUpInfo.hStdOutput = latitudeReadOutHandle;
latitudeStartUpInfo.hStdError = latitudeReadOutHandle;
应该是
latitudeStartUpInfo.hStdOutput = latitudeWriteOutHandle;
latitudeStartUpInfo.hStdError = latitudeWriteOutHandle;
我终于意识到我的代码出了什么问题。 首先,我要感谢 Ben Voigt 的正确答案。 所以这是开始为我工作的代码。
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);
}
}
}
对于缓冲区,您需要使用
char
而不是 wchar_t
。