Я пишу службу Windows на C ++ (Visual Studio 2010), и эта служба должна отправлять файл на удаленный сервер через безопасную копию (для этого я использую pscp.exe).
Итак, я использую функцию system для запуска pscp.exe, и при запуске в качестве обычного приложения все работает нормально.
Но если я пытаюсь запустить как службу, служба запускает pscp.exe (я вижу это в диспетчере задач), но pscp.exe зависает и ничего не отправляет на удаленный хост. И даже если я остановлю службу, мне придется самому убить процесс pscp.
Я читал на некоторых форумах, чтобы разрешить службе "взаимодействовать с рабочим столом", но это не решило мою проблему.
Я также попытался изменить учетную запись пользователя, с которой служба входит в систему, но безрезультатно.
Любые идеи?
Кажется, что очень сложно запустить внешнюю программу из службы Windows, даже если эта внешняя программа не имеет графического интерфейса пользователя, например pscp.exe.
Спасибо!
- Аугусто Каринги
Ответ 1 · Steve Townsend
Каковы ваши варианты pscp вызова? Если есть опция "без звука", используйте ее, чтобы избежать взаимодействия с консолью. Часто это -q или /q.
Имейте в виду, что любое запущенное приложение будет работать под той же учетной записью, что и ваша служба. Есть ли у этой учетной записи разрешения делать то, что вы от нее просите? Правильный ли контекст (каталог выполнения, путь) для pscp, чтобы делать то, что вы хотите?
Ответ 2 · Raiv
Вы можете попробовать использовать олицетворение. Что-то вроде этого...
wchar_t* cmPath=readRegistryString(L"Software\\" TO_WCHAR(ORG_NAME) L"\\" TO_WCHAR(APP_NAME) L"\\" TO_WCHAR(APPLICATION_GROUP),TO_WCHAR(APPLICATION_EXEC_PATH));
if (!cmPath)
{
return false;
}
HANDLE userToken=NULL;
DWORD sessId=WTSGetActiveConsoleSessionId ();
if((long)sessId==-1)
{
sessId=0;
}
WTSQueryUserToken (sessId, &userToken);
bool result=false;
if(userToken/**/ )
{
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa,sizeof(SECURITY_ATTRIBUTES));
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
STARTUPINFOW si;
ZeroMemory(&si,sizeof(STARTUPINFOW));
si.cb=sizeof(STARTUPINFOW);
PROCESS_INFORMATION pi;
ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
CStringW str= L"\"";
str=str+cmPath;
str=str+L"\"";
str.Replace(L"/",L"\\");
if(CreateProcessAsUserW(userToken,NULL,str.GetBuffer(),NULL,NULL,false,NULL,NULL,NULL,&si,&pi))
{
result=true;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
{
DWORD err = GetLastError();
//nop;
}
}
if(userToken)
CloseHandle(userToken);
delete[] cmPath;
этот фрагмент кода я использую для вызова приложения с графическим интерфейсом пользователя из службы, но я думаю, что для консольного приложения особых изменений не требуется.