Webservice call exe file

(以下内容,十分感谢武汉同事-陈青,在他提供的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)的,还是有异常发生,可能还需要其它的设置吧。