簡體   English   中英

無法從 Windows 服務托管的 wcf 啟動 WinWord

[英]Can't launch WinWord from windows service hosted wcf

我有這個 WCF。 當我從 Chrome 瀏覽器調用它時,如http://localhost:8733/doc/run/Test.doc wcf-service 返回:

Tect.doc Succeed

但是Word的窗口沒有出現。 我應該在代碼中更改什么才能打開 Word 的窗口?

namespace WordDavService
{
    [ServiceContract]
    public interface IWcfDocOpen
    {
        [WebGet(UriTemplate = "/run/{Path}", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        string Run(string Path);
    }

    [AspNetCompatibilityRequirements(RequirementsMode =
        AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
    public class DocOpenWcfService : IWcfDocOpen
    {
        //public static void Main() 

        public string Run(string Path)
        {
            Task<string> thread = Task<string>.Factory.StartNew(() =>
               { return DocOpenWcfService.OpenWord(Path); });
            Task.WaitAll(thread);
            return Path+thread.Result;
        }

        protected static string OpenWord(string Path)
        {
            Word._Application application = null; ;
            Word._Document document = null; ;

            Object _Path = Path;
            try
            {
                application = new Word.Application();
                if (!string.IsNullOrEmpty(_Path.ToString()))
                    document = application.Documents.Open(ref _Path);
                application.Visible = true;
            }
            catch (Exception error)
            {
                try
                {
                    document.Close();
                }
                catch { }
                try
                {
                    application.Quit();
                }
                catch { }
                document = null;
                application = null;
                return error.Message+"innerExeption: "+error.InnerException.Message;
            }
            return "Succeed";
        }
    }
}

這是如何從 Windows 服務啟動 GUI 進程的說明

這是我的認識:

namespace WordDavService
{

[ServiceContract]
public interface IWcfDocOpen
{

    [WebGet(UriTemplate = "/run/{Path}", ResponseFormat = WebMessageFormat.Json)]
    [OperationContract]
    string Run(string Path);
}

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class DocOpenWcfService : IWcfDocOpen
{
    //public static void Main() 

    public string Run(string _Path)
    {

        int session = WinAPI.WTSGetActiveConsoleSessionId();
        if (session ==0xFFFFFFFF)
        {
            return "NoActiveSession";
        }

        IntPtr userToken;
        bool res = WinAPI.WTSQueryUserToken(session, out userToken);


        string path =  "C:\\Windows\\LauncherWord.exe";
        string dir = Path.GetDirectoryName(path);
       WinAPI.STARTUPINFO si = new WinAPI.STARTUPINFO();
        si.lpDesktop = "winsta0\\default";
        si.cb = (uint)Marshal.SizeOf(si);

        WinAPI.PROCESS_INFORMATION pi = new WinAPI.PROCESS_INFORMATION();
        WinAPI.SECURITY_ATTRIBUTES sa = new WinAPI.SECURITY_ATTRIBUTES();
        sa.bInheritHandle = true;
        sa.length = Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = IntPtr.Zero;

        if (!WinAPI.CreateProcessAsUser(userToken,       // user token
                                        path+" "+_Path,           // exexutable path
                                        "",   // arguments
                                        ref sa,         // process security attributes ( none )
                                        ref sa,         // thread  security attributes ( none )
                                        true,          // inherit handles?
                                        0x02000000,              // creation flags
                                        IntPtr.Zero,    // environment variables
                                        dir,            // current directory of the new process
                                        ref si,         // startup info
                                        ref pi))        // receive process information in pi
        {
            int error = Marshal.GetLastWin32Error();
            return "Error CreateProcessAsUser:" + error + " File: " + path + " " + _Path;
        }
        else
            return "Success:" + path + " " + _Path;

    }

}

public static class WinAPI
{
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int WTSGetActiveConsoleSessionId();

   [DllImport("wtsapi32.dll", SetLastError = true)]
    public static extern bool WTSQueryUserToken(int Session,[Out] out IntPtr phToken);

    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public uint dwProcessId;
        public uint dwThreadId;
    }

    public struct STARTUPINFO
    {
        public uint cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public uint dwX;
        public uint dwY;
        public uint dwXSize;
        public uint dwYSize;
        public uint dwXCountChars;
        public uint dwYCountChars;
        public uint dwFillAttribute;
        public uint dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    public struct SECURITY_ATTRIBUTES
    {
        public int length;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }

  [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser",      SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool  CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, 
                      ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, 
                      bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
                      string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, 
                      ref PROCESS_INFORMATION lpProcessInformation);

    }
}

此服務會啟動 LauncherWord.exe,它會像這樣啟動 Word:

namespace LauncherWord
{
class Program
{
    static void Main(string[] args)
    {
        string Path = "";
        if (args.Length > 0)
            Path = args[0];
        OpenWord(Path);

    }

    protected static string OpenWord(string Path)
    {
        Word._Application application = null; ;
        Word._Document document = null; ;

        Object _Path = Path;
        try
        {
            application = new Word.Application();

            if (!string.IsNullOrEmpty(_Path.ToString()))
                document = application.Documents.Open(ref _Path,Type.Missing,(object)false);
            application.Visible = true;

        }
        catch (Exception error)
        {
            try
            {
                document.Close();
            }
            catch { }
            try
            {
                application.Quit();
            }
            catch { }
            document = null;
            application = null;
            return error.Message + "innerExeption: " + error.InnerException.Message;
        }

        return "Succed";
    }
  }
}

但結果並不好,因為 Word 以幾個關於不可訪問文件的錯誤開始。 並且 Word 的行為不穩定,可能無法訪問。

有沒有人可以建議我如何使 Word 的流程工作穩定?

我不確定您指的是什么錯誤,但是您應該能夠通過在嘗試打開這些文件之前檢查這些文件是否存在來防止有關無法訪問的文件等的錯誤? 自動化 Word 通常涉及很多像這樣的防御性編程。

但是,我認為你有一個更大的問題。 從 Windows 服務自動化 Word 是“不贊成的”,因為它不受 Microsoft 支持,並且可能違反許可條款。

它可以完成(很多人都這樣做 - 就像我一樣),但一般來說,人們會在沒有登錄用戶的專用服務器上執行此操作,並且可能也在使用 Office。 如果在用戶的 PC 上執行此操作,我會非常緊張,因為您的服務和用戶可能同時運行 Word。

如果您仍想采用這種方法,如果您能描述您所看到的具體錯誤或不穩定性,將會很有幫助。

另請參閱此答案,它可能會讓您走得更遠。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM