繁体   English   中英

FileSystemWatcher不适用于从Windows服务创建的文件

[英]FileSystemWatcher does not work on files created from windows service

我正在从在LocalSystem帐户下运行的Windows服务创建文件。 我有一个Windows应用程序,该应用程序监视在其中创建文件的指定文件夹。 我正在使用FileSystemWatcher,但不会触发。 Windows资源管理器中的文件图标是一个挂锁图标。 如何从Windows服务创建此文件,以便可以从Windows用户帐户访问该文件?

FileWatcher是片状的。 如果您正在观看网络驱动器上的文件夹,也会出现问题。 我已经看到有十几个或更多使用FileWatcher的应用程序,而且每个人中的每个人都不止一次无法识别创建文件的时间。

我将使用定时事件来备份FileWatcher,该事件检查新文件或修改过的文件。 这样,如果FileWatcher无法识别事件,计时器将捕获该事件。

我认为最好亲自构建一个服务来监视该文件夹,因为这样您就可以将该服务上的帐户设置为LocalSystem,并且如果该帐户与正在创建该文件的其他服务位于同一台计算机上,那应该没问题。 但是,我想代码应该类似于从应用程序执行的代码,但有一个额外的层:模拟。 是否使用FileSystemWatcher确实与它无关。 权限是权限,本身就是一个单独的动物。

我对自己构建的服务进行类似文件检查的方式是通过计时器完成的。 您可以将其与查找文件属性(例如File.Exists()File.GetCreationTime()以及File.GetLastWriteTime()以确定文件是否存在,何时到达以及何时被最后修改。 您会知道是否已处理该文件,如果该文件的时间间隔超过了计时器的运行间隔。

参考: http : //www.csharp-examples.net/file-creation-modification-time/

对我来说,每当我处理该文件时,我就让我的应用程序将其删除,因此,我要做的就是File.Exists()检查是否还有另一个文件。

下面的代码是一种用于定期查找文件的服务,并且在下一部分中,我还稍微集成了您需要做的(出于模拟目的而没有用),我将在下面进行解释。 您也许可以使它适应您的应用程序:

using System;
using System.ServiceProcess;
using System.Threading;
using System.Timers;

namespace MyNamespace
{
    public partial class Service1:  ServiceBase
    {
        Thread syncThread = null;
        System.Timers.Timer timer1;
        string filePath = @"C:\myfile.txt";

        public Service1()
        {
            InitializeComponent();             
        }

        protected override void OnStart(string[] args)
        {
            timer1 = new System.Timers.Timer();
            timer1.Interval = 60000; // 1 min
            timer1.Enabled = true;
            timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
            timer1.Start();
        }
        protected override void OnStop()
        {
            syncThread.Abort();
            timer1.Stop();
        }
        protected void timer1_Elapsed(object sender, ElapsedEventArgs e)
        {
            syncThread = new Thread(new ThreadStart(doThread));
            syncThread.Start();
        }
        protected void doThread()
        {
            // This will run for each timer interval that elapses
            // in its own separate thread, and each thread will
            // end when the processing in this function ends            

            // You'll need to develop a strategy for getting these 
            // into your app
            string username, domainName, password;

            // Log the domain service account in, here... 
            bool returnValue = LogonUser(userName, domainName, password,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                out safeTokenHandle);

            if (!returnValue) return;  // not logged in - report this

            using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
            {
                using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) 
                {                 
                    bool fileAbsent = true;
                    string myFileText = String.Empty;
                    if (File.Exists(filePath))
                    {
                        fileAbsent = false;
                        FileStream fs = new FileStream(filePath, FileMode.Open);
                        StreamReader sr = new StreamReader(fs)
                        myFileText = sr.ReadToEnd();
                        sr.Close();
                        fs.Close();
                        File.Delete(filePath);
                    }
                    else
                    {
                        // report that file does not exist
                    }

                    if (myFileText != String.Empty)  // content found
                    {
                        // do processing here
                    }
                    else
                    {
                        //if (fileAbsent == false)
                        // report file was found, but empty
                    }
                } 
            }    
        }
    }
}

请注意,如果有人没有打开您的应用程序正在监视的文件的权限,并且他们已经登录并且运行了您正在构建的该应用程序,那么您将无法打开它。 该应用程序使用与登录用户相同的文件权限,除非您实施代码以其他方式对确实拥有该文件权限的用户使用WindowsImpersonationContext 但是您将无法在应用程序中模拟Windows LocalSystem帐户,因为您没有该帐户的凭据,因此,最佳做法是在需要额外权限的域帐户下运行服务,因为这样。 而是,应将服务设置为在新的或现有的域服务帐户下运行,该帐户应具有您知道其密码的文件的权限。 然后,您可以在您的应用程序中模拟该域帐户,就像您实际使用该帐户登录一样。

下面的类是从MSDN站点复制并格式化 ,类似于您必须适应应用程序的类-您必须将其与上面的计时器代码结合起来。 这将是您必须提示或存储有权访问该文件的域帐户的凭据的位置。 using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) { ... }区域内,您将以模拟用户的身份进行文件读取和处理。 我已经在上面的代码中添加了LogonUser()并对其进行了LogonUser() ,但是您将必须包括该函数,常量以及下面所有我没有提供的其他缺少的引用:

public class ImpersonationDemo
{
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    // Test harness.
    // If you incorporate this code into a DLL, be sure to demand FullTrust.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public static void Main(string[] args)
    {
        SafeTokenHandle safeTokenHandle;
        try
        {
            string userName, domainName;
            // Get the user token for the specified user, domain, and password using the
            // unmanaged LogonUser method.
            // The local machine name can be used for the domain name to impersonate a user on this machine.
            Console.Write("Enter the name of the domain on which to log on: ");
            domainName = Console.ReadLine();

            Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);
            userName = Console.ReadLine();

            Console.Write("Enter the password for {0}: ", userName);

            const int LOGON32_PROVIDER_DEFAULT = 0;
            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_LOGON_INTERACTIVE = 2;

            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                out safeTokenHandle);

            Console.WriteLine("LogonUser called.");

            if (false == returnValue)
            {
                int ret = Marshal.GetLastWin32Error();
                Console.WriteLine("LogonUser failed with error code : {0}", ret);
                throw new System.ComponentModel.Win32Exception(ret);
            }
            using (safeTokenHandle)
            {
                Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
                Console.WriteLine("Value of Windows NT token: " + safeTokenHandle);

                // Check the identity.
                Console.WriteLine("Before impersonation: "
                    + WindowsIdentity.GetCurrent().Name);
                // Use the token handle returned by LogonUser.
                using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
                {
                    using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                    {

                        // Check the identity.
                        Console.WriteLine("After impersonation: "
                            + WindowsIdentity.GetCurrent().Name);
                    }
                }
                // Releasing the context object stops the impersonation
                // Check the identity.
                Console.WriteLine("After closing the context: " + WindowsIdentity.GetCurrent().Name);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception occurred. " + ex.Message);
        }

    }
}
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private SafeTokenHandle()
        : base(true)
    {
    }

    [DllImport("kernel32.dll")]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [SuppressUnmanagedCodeSecurity]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr handle);

    protected override bool ReleaseHandle()
    {
        return CloseHandle(handle);
    }
}

参考: https : //msdn.microsoft.com/zh-cn/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM