代码改变世界

编写服务程序所遇到的问题

2015-06-03 17:13  sylar_liang  阅读(486)  评论(0编辑  收藏  举报

1.How to Create a Windows NT/ Windows 2000 Service翻译描述

网址:

http://blog.csdn.net/delphiwcdj/article/details/4581671

 

1.VS2008 CLR 建立WINDOWS服务程序 调用外部EXE文件

网址:

https://social.msdn.microsoft.com/Forums/vstudio/zh-CN/1876f300-16e5-49d6-b79e-b2c37e8806b8/vs2008-clr-windows-exe?forum=visualstudio2012zhcn

 2.開發AP無法在Vista跟Win7正常執行

网址:

https://social.msdn.microsoft.com/Forums/zh-TW/ea1e7af2-919a-4480-a830-d2a111698c16/apvistawin7

 

3.服务程序中无法调用外部exe

1>穿透Session 0 隔离

网址:

http://www.cnblogs.com/gnielee/archive/2010/04/07/session0-isolation-part1.html

 

描述: 系统服务的Sesion 0隔离

http://tech.sina.com.cn/s/2009-09-24/07561078945.shtml

解决:

1>取得系统的Token句柄

2>根据此句柄调用CreateProcessAsUser函数来创建进程,此时创建的进程是运行在session 1.

 

网址:http://bbs.csdn.net/topics/390431360

通过CREATEPROCESSASUSER创建的进程,虽然任务管理器查看已经是用户权限了,但是里面执行的结果却是SYSTEM权限的,环境变量什么的都是SYSTEM的。

 

4.CreateProcessAsUser无法将创建的新进程前置

网址: 

http://www.jscto.net/html/32840.html

 

如果你是用服务以已登录用户的名义创建的notepad进程的话:

你的服务和notepad属于不同的会话,属于不同的桌面,因此EnumWindows(findwindow)等局限于当前桌面的函数自然是查不到窗口的。

创建进程并置顶是有条件的:条件列表:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
Windows 2000/XP: No menus are active.

 

解决: CreateProcessAsUser创建一个临时的exe,再用这个exe来调用想要运行的程序,则可以实现新进程前置。

 

5.将基于MFC的对话框应用程序修改为服务程序 

网址:

http://blog.csdn.net/delphiwcdj/article/details/4585680

未做验证。

 

6.

1. 有人说为什么自己不重写一个外部的exe,可以避免调用?
这个我也想过,如果重写外部exe那么简单的话,说都不愿意去调用。我这个主要是因为需要调用到一些底层的驱动,外部exe把这些都写好了,所以直接调用很方便。当然可以自己写的,我也试过,需要调用一些dll动态库,但是一些函数的调用却返回错误,查了原因,还是因为session的问题。

2. 关于“勾选允许与桌面互动”选项
最开始大部分时间浪费在这里。关于调用外部exe的方式有很多种,然后很多人建议说要勾选“允许与桌面互动”,我勾选了却和原来一样。然后我就以为是我调用外部exe的方式不对,搜索各种调用外部exe的方法,最后发现,即使可以,也是弹出一个消息框,可以在另外一个桌面上显示外部exe的窗口,不是我所想要的。
网上的很多东西都是比较老了,这些代码以及方法应该都是针对xp以及以前的系统,对于vista和win7就无效了,最开始不知道,浪费了很多时间。

3. 服务隔离
这里要感谢“gomoku”,你的回答让我知道了我错在哪里了,但是你的回答也不完全正确。我仔细阅读了微软的document,发现虽然默认情况下,服务是运行在session 0下的,与普通的应用程序不在一个session,所以不能互动,但是我们可以利用函数“CreateProcessAsUser”来创建应用程序session下的进程,从而调用外部exe。拨开云雾见日出。走到这一步,问题就明朗,方向也明确了。
这里重发一下链接,以后遇到同样问题的可以参考:http://msdn.microsoft.com/zh-cn/library/windows/hardware/gg463353.aspx

4. 如何利用用createProcessAsUser呢?
看了这个函数的介绍,在网上也有很多例子,大部分是说,需要知道当前用户的用户名和密码,但是这对于个人测试用还可以,如果你作为一个软件release给客户显然不行。网上有高人给出一个解决方法,就是得到一些系统进程的进程token,比如winlog.exe,explorer.exe,然后利用这些进程的token来创建自己的进程。有位高人给出了源码,现在找不到那个链接了,于是自己写了篇文章,把那位大哥的源码贴出来了,如果需要可以参考。http://blog.csdn.net/nonths/article/details/8833854

关于session,我觉得作为一个程序员,还是有必要深入了解下的。

 

6. 令牌写法,未验证

DWORD WINAPI TimeServiceThread(LPVOID)
{
while (!g_Stop)
{
Sleep(5000);

// 为了显示更加复杂的用户界面,我们需要从Session 0创建
// 一个进程,但是这个进程是运行在用户环境下。
// 我们可以使用CreateProcessAsUser实现这一功能。

BOOL bSuccess = FALSE;
STARTUPINFO si = {0};
// 进程信息
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);

// 获得当前Session ID
DWORD dwSessionID = WTSGetActiveConsoleSessionId();

HANDLE hToken = NULL;
// 获得当前Session的用户令牌
if (WTSQueryUserToken(dwSessionID, &hToken) == FALSE)
{
goto Cleanup;
}

// 复制令牌
HANDLE hDuplicatedToken = NULL;
if (DuplicateTokenEx(hToken,
MAXIMUM_ALLOWED, NULL,
SecurityIdentification, TokenPrimary,
&hDuplicatedToken) == FALSE)
{
goto Cleanup;
}

// 创建用户Session环境
LPVOID lpEnvironment = NULL;
if (CreateEnvironmentBlock(&lpEnvironment,
hDuplicatedToken, FALSE) == FALSE)
{
goto Cleanup;
}

// 获得复杂界面的名字,也就是获得可执行文件的路径
WCHAR lpszClientPath[MAX_PATH];
if (GetModuleFileName(NULL, lpszClientPath, MAX_PATH) == 0)
{
goto Cleanup;
}
PathRemoveFileSpec(lpszClientPath);
wcscat_s(lpszClientPath,
sizeof(lpszClientPath)/sizeof(WCHAR),
L"\TimeServiceClient.exe");

// 在复制的用户Session下执行应用程序,创建进程。
// 通过这个进程,就可以显示各种复杂的用户界面了
if (CreateProcessAsUser(hDuplicatedToken,
lpszClientPath, NULL, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
lpEnvironment, NULL, &si, &pi) == FALSE)
{
goto Cleanup;
}

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
bSuccess = TRUE;

// 清理工作

Cleanup:
if (!bSuccess)
{
ShowMessage(L"无法创建复杂UI", L"错误");
}

if (hToken != NULL)
CloseHandle(hToken);
if (hDuplicatedToken != NULL)
CloseHandle(hDuplicatedToken);
if (lpEnvironment != NULL)
DestroyEnvironmentBlock(lpEnvironment);
}

return 0;
}

7.GetTokenByName 与 CreateProcessAsUser 写法,已验证可行

BOOL GetTokenByName(HANDLE *hToken,LPSTR lpName)
{
if(!lpName){
return FALSE;
}

HANDLE hProcessSnap = NULL;
BOOL bRet = FALSE;
PROCESSENTRY32 pe32 = {0};

hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return (FALSE);

pe32.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(hProcessSnap, &pe32))
{
do
{
if(!strcmp(_strupr(pe32.szExeFile),_strupr(lpName)))
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE,pe32.th32ProcessID);
bRet = OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,hToken);
CloseHandle (hProcessSnap);
return (bRet);
}
}
while (Process32Next(hProcessSnap, &pe32));
bRet = TRUE;
}
else
bRet = FALSE;

CloseHandle (hProcessSnap);
return (bRet);
}

BOOL RunProcess()
{
TCHAR awExecuteFile[512];
HANDLE hToken;
if(!GetTokenByName(&hToken,"EXPLORER.EXE"))
{
return FALSE;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = TEXT("winsta0\\default");
GetSystemDirectory(awExecuteFile, 512);
strcat(awExecuteFile, "\\spool\\drivers\\w32x86\\3\\GLP_AP.exe ");


BOOL bResult = CreateProcessAsUser(
hToken,
awExecuteFile,
NULL,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi);

CloseHandle(hToken);
if(bResult)
{
OutputDebugString("CreateProcessAsUser ok!\r\n");
}
else
{
OutputDebugString("CreateProcessAsUser false!\r\n");
}
return bResult;
}