(以下内容,十分感谢武汉同事-陈青,在他提供的Sample基础上,偶才找到了解决办法)
///Webservice Source Code
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Diagnostics;
using System.Collections;
using System.Threading;
using System.Security;
using System.IO;
using System.Text;
using System.Messaging;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
//[assembly: SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode = true)]
//[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "FullTrust")]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
private static ArrayList runningBatch = new ArrayList(); // 记录running的Batch程序
// 模拟身份时登录用的API,得到一个用户句柄
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(String lpszUsername,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
public static System.Security.Principal.WindowsIdentity wi = null; // Windows身份对象
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
public Service () {
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
public string CallExeByThread()
{
// log 输出
Output(DateTime.Now.ToString() + "t call CallExeByThread….");
foreach (string s in runningBatch)
{
Output("running=" + s);
}
string retString = "OK"; // return string, OK is success
//正常情况下,调用该Webservice的人要传入batchId,然后Webservice根据这个ID找到相应的exe文件,
//此处只是验证webservice是否可以调用可执行程序,所以设定了hard code。
string batchId = "aaaaaaa";
//如果缓存中可以找到这个batchId,则说明该Batch正在运行中。
if (runningBatch.Contains(batchId))
{
retString = "running";
}
else
{
if (wi == null)//如果模拟身份是空则建立模拟身份
{
IntPtr h = IntPtr.Zero;
LogonUser("test", "", "wits2008", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref h);
wi = new WindowsIdentity(h);
}
// 开始以模拟的身份进行工作
using (System.Security.Principal.WindowsImpersonationContext impersonatedUser = wi.Impersonate())
{
//以多线程的方式进行Batch的调用
ParameterizedThreadStart batThreadStart = new ParameterizedThreadStart(
StartBatchThread);
Thread batThread = new Thread(batThreadStart);
batThread.Name = batchId;
batThread.Start(batchId);
//impersonatedUser.Undo(); // 结束模拟
//记录Batch的运行状态
runningBatch.Add(batchId);
}
}
Output(DateTime.Now.ToString() + "t end CallExeByThread….");
return retString;
}
private void StartBatchThread(object batchId)
{
//Output(DateTime.Now.ToString() + "t call StartBatchThread….");
try
{
//正常程序是传入exe文件名,不是写死的
string exeFilePath = @"c:SampleBatch.exe";
ProcessStartInfo program = new ProcessStartInfo();
program.FileName = exeFilePath;
program.UseShellExecute = false;
program.CreateNoWindow = true;
Process p = Process.Start(program);
p.WaitForExit();
p.Close();
}
catch
{
}
//如果程序执行完毕,则清除缓存中的状态
lock (runningBatch.SyncRoot)
{
runningBatch.Remove(batchId);
}
//Output(DateTime.Now.ToString() + "t end StartBatchThread….");
}
private void Output(string s)
{
using (StreamWriter sw = new StreamWriter(@"C:logsExelog.txt", true, Encoding.Default))
{
StringBuilder sb = new StringBuilder();
sb.Append(s).Append(Environment.NewLine);
sw.Write(sb.ToString());
}
}
}
原理比较简单,在调用可执行文件时,要以服务器上有足够权限的用户身份来运行才可以。目前这种方式可以正常调用Console App,如果是Windows App(包含Form)的,还是有异常发生,可能还需要其它的设置吧。