如何让服务启动另一个程序

时间:2022-08-29 14:54:54

用Windows服务来启动带UI界面的程序 很多同学使用服务来单纯的启动另一个程序(WinExe,ShellExe,CreateProcess)结果发现我们的程序没界面但有进程,那是为什么呢?服务启动UI程序不能直接CreateProcess(),否则因为service session,程序UI不能看见,所以 我们需要拿到当前explorer.exe的token,然后CreateProcessAsUser模拟当前用户启动进程这样就可以显示界面了


第一步,得到explorer.exe环境的token
DWORD INTER_GetExplorerToken( PHANDLE phExplorerToken )
{
    DWORD       dwStatus = ERROR_FILE_NOT_FOUND;
    BOOL        bRet = FALSE;   
    HANDLE      hProcess = NULL;   
    HANDLE      hProcessSnap = NULL ;   
    char        szExplorerPath[MAX_PATH] = { 0 };   
    char        FileName[MAX_PATH] = { 0 };   
    PROCESSENTRY32 pe32 = { 0 };
 
    try  
    {   
        hProcessSnap = ::CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS , 0 );
        if( hProcessSnap == INVALID_HANDLE_VALUE )     
        {   
            dwStatus = GetLastError();
        }
        else
        {
            pe32.dwSize = sizeof( PROCESSENTRY32 );
            int bMore = ::Process32First(hProcessSnap, &pe32);
            while( bMore )
            {
                if ( ::wcscmp(pe32.szExeFile, _T("explorer.exe")) == 0 )
                { 
                    hProcess = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
                    if( OpenProcessToken(hProcess , TOKEN_ALL_ACCESS  , phExplorerToken) )
                    {
                        dwStatus = 0;
                    }
                    else
                    {
                        dwStatus = GetLastError();
                    }
                    break;
                }   
                bMore = ::Process32Next( hProcessSnap, &pe32 );
            }
        }
    }
    catch(...)
    {
    }
     
    if( hProcess )
    {
        CloseHandle( hProcess );
    }
    if( hProcessSnap )
    {
        CloseHandle ( hProcessSnap );
    }
  
    return dwStatus;
}
 
第二步,启动程序
void RunProcess(CString szExeFile, CString szDirectory)
{
    HANDLE hToken = NULL;
    if( INTER_GetExplorerToken( &hToken ) == 0 )
    {
        PROCESS_INFORMATION pi = { 0 };
        SECURITY_ATTRIBUTES sa = { 0 };
        sa.nLength = sizeof( SECURITY_ATTRIBUTES ); 
        STARTUPINFO si = { 0 };
        si.dwFlags = STARTF_USESHOWWINDOW;
        si.cb = sizeof( STARTUPINFO );
        si.wShowWindow = SW_SHOW;
        CreateProcessAsUser( hToken, szExeFile, NULL, &sa, &sa, FALSE, NORMAL_PRIORITY_CLASS| CREATE_NEW_CONSOLE, NULL, szDirectory, &si, &pi );
    }
}
 
 
最后,大家注意了我使用了CreateProcessAsUser 的 lpCurrentDirectory 参数,这个对希望使用配置文件(ini)来说很重要,如果不设置该参数那么所读取的配置的路径将会和你服务路径一样