-1

I have this WCF. When i call it from Chrome-browser like http://localhost:8733/doc/run/Test.doc the wcf-service returns:

Tect.doc Succeed

But the Word's window doesn't appear. What should i change in code to get the Word's window opened?

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";
        }
    }
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • 1
    Why would you want to open an interactive desktop app on your server? – H H Oct 09 '15 at 12:51
  • I have the link that is referred to the WebDav .docx document and i want open this document directly in Word. And this is not a server, it's just Windows service hosted on client's machine. – Макс Б Oct 09 '15 at 13:16
  • So you mean that word is not openning on the calling machine, or that word is not openning on the machine running the windows service? – tom redfern Oct 09 '15 at 14:58
  • This is the same machines. On a client's machine hosts the windows service with wcf. When somebody calls this wcf like http://localhost:8733/doc/run/Test.doc, it should localy launch the Word with a file that's name was passed like a parameter in Url – Макс Б Oct 10 '15 at 04:53

2 Answers2

0

This is an explanation how to launch GUI-process from the windows service.

And this is my realisation:

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);

    }
}

This service launches the LauncherWord.exe which starts the Word like this:

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";
    }
  }
}

But the result is not good because the Word starts with several errors concerning the not-accessible-files. And the behavior of the Word is not stable and it can be inaccessible.

Is there anybody who could advise me how to make the work of the process with Word stable?

0

I'm not sure what errors you're referring to, but you should be able to prevent errors regarding inaccessible files, etc. by checking for the existence of those files before you attempt to open them? Automating Word generally involves a lot of defensive programming like this.

However, I think you have a bigger problem. It's "frowned-upon" to automate Word from a Windows Service, in that it's not supported by Microsoft, and may violate the license terms.

It can be done (and lots of people do it - as have I), but generally speaking people will do this on a dedicated server that has no logged-in user who might also be using Office. I would be very nervous about doing it on a user's PC, where both your service and the user are potentially running Word at the same time.

If you still want to pursue this approach, it would be helpful if you could describe the specific errors or instability you're seeing.

See also this answer which might get you a little further.

Community
  • 1
  • 1
Gary McGill
  • 26,400
  • 25
  • 118
  • 202
  • When the Wrod starts it alerts 2 errors that it can't save files MSO1049.ad and MSO.ACLMSO1049.ad because possibly i haven't rights to do it or the files have read-only access. After that the Word doesn't open file that i specify to it thru the input parameter _Path in this code:' document = application.Documents.Open(ref _Path,Type.Missing,(object)false);' Beside that i can't open a file using Word's interface but can create new one. And i can't close Word's window only using Task Manager. – Макс Б Oct 13 '15 at 06:23