1

5分ごとにスクリーンショットを取得してサーバーに保存するC#アプリを作成しました。タイマー、2 つのスレッド、いくつかのメソッド (ping srv、フォルダーの確認、スクリーンショットの取得など) です。

プロセス (exe) としては問題なく動作しますが、サービスとしてインストールする必要があります。installutil (フレームワーク サービス インストーラー) を使用してインストールしています。

私の問題は、サービスとしてインストールすると、スクリーンショットが撮れないことです。サービスを停止するときは、いくつか引き出します。適切な解像度ではなく、黒です。

エグゼクティブコードが間違っていると思います(メインを参照)。複数の main メソッドを持つことはできないため、どこに配置すればよいかわかりません。助けてください。

主なアプリケーションのコード:

I've deleted some not important code. 

    using System;
    using System.Threading;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Windows.Forms;
    //using System.Timers;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Net.NetworkInformation;
    using System.ComponentModel;
    using System.Configuration.Install;

    namespace LogWriterService
    {
        static class Program
        {
            public static int TimeO = 5;  // zpoždění časovače v minutách
            private static bool Online;
            private static bool active = false;

            public static String GetIP()
            {
                // ...  
                // returns IP like xxx.xxx.xxx.xxx
                // ...   
            }

            // Test dostupnosti serveru
            public static bool PingTest()
            {
                // ... 
                // return true if server is reachable
                // ... 
            }


            /*
             * Z Windows.Forms _ screenů získá obrazová data, která uloží na
             * server jako ../[IP]/[současný_systémový_čas].jpg
             */
            public static void  ScreenShot()        //Bitmap
            {
                Int64 CurrTime = Int64.Parse(DateTime.Now.ToString("yyyyMMddhhmmss")); //yyyyMMddhhmmss

                Rectangle bounds = Rectangle.Empty;

                foreach (Screen s in Screen.AllScreens)
                    bounds = Rectangle.Union(bounds, s.Bounds);

                Bitmap screenShotBMP = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);   // PixelFormat.Format32bppArgb

                Graphics screenShotGraphics = Graphics.FromImage(screenShotBMP);

                screenShotGraphics.CopyFromScreen(bounds.X, bounds.Y,
                    0, 0, bounds.Size, CopyPixelOperation.SourceCopy);

                string path = null;  //"D:/TEMP/" + CurrTime + ".jpg";  // GetIP()

                // Ukládání obrázků do dočasné složky a přesun, pokud se připojí
                if (PingTest() == true)
                {
                    path = "//10.0.0.10/Upload/screen/test/" + GetIP() + "/" + CurrTime + ".jpg";
                    string path2 = "//10.0.0.10/Upload/screen/test/" + GetIP() + "/";
                    Online = true;
                    if (Directory.Exists(path2))
                    {
                        MoveCached();
                    }
                    else
                    {
                        Console.WriteLine("Online slozka neni dostupna.");
                    }
                } else {
                    Console.WriteLine("Caching .. ");
                    path = "C:/TEMP/" + CurrTime + ".jpg";  // "C:/TEMP/" + GetIP() + "/" + CurrTime + ".jpg"

                    string LPath = @"c:\TEMP";
                    if (!Directory.Exists(LPath))
                    {
                        DirectoryInfo di = Directory.CreateDirectory(LPath);
                        di.Attributes = FileAttributes.Directory | FileAttributes.Hidden;

                        Console.WriteLine("Lokalni slozka neexistuje. Vytvarim ..");
                    }
                    Online = false;
                }

                screenShotBMP.Save(path, ImageFormat.Jpeg); // C:\\test\\test.jpg        
                screenShotGraphics.Dispose();
                screenShotBMP.Dispose();

                return; //screenShotBMP;
            }


            /*
             * Přesune cache soubory (za dobu offline) na server
             */
            public static void MoveCached()
            {
                // ... 
                // after conect, move localy saved screenshots to server
                // ... 
            }

            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            static void Main()
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
                { 
                    new Service1() 
                };
                ServiceBase.Run(ServicesToRun);


                // Vytvoří událost signalizující hranici odpočtu ve  
                // zpětném volání časovače
                AutoResetEvent autoEvent = new AutoResetEvent(false);

                // Počet průchodů timeru
                StatusChecker statusChecker = new StatusChecker(Timeout.Infinite); //  1440

                // Vytvoří odvozeného delegáta, který vyvolá metody pro časovač
                TimerCallback tcb = statusChecker.CheckStatus;

                // Create a timer that signals the delegate to invoke 
                // CheckStatus after one second, and every 1/4 second 
                // thereafter.
                System.Threading.Timer stateTimer = new System.Threading.Timer(tcb, autoEvent, 1000, TimeO * 1000); // TimeO * 1000 * 60 * 12 * 5, 250

                // When autoEvent signals, change the period to every
                // 1/2 second.
                autoEvent.WaitOne(15000, false);
                stateTimer.Change(0, TimeO * 1000 * 60);        // TimeO * 1000 * 60
                Console.WriteLine("menim poprve..");

                // When autoEvent signals the second time, dispose of 
                // the timer.
                autoEvent.WaitOne(Timeout.Infinite, false);
                stateTimer.Change(0, TimeO * 1000 * 60);        // TimeO * 1000 * 60
                Console.WriteLine("menim podruhe..");
                //stateTimer.Dispose();


                // Garbage collector
                GC.Collect();
                GC.WaitForPendingFinalizers();

            }
        }
        }

        class StatusChecker
        {
        private int invokeCount;
        private int maxCount;
        Int64 CurrTime = Int64.Parse(DateTime.Now.ToString("hh"));  //  screeny od 6:00 do 16:00

        public StatusChecker(int count)
        {
            invokeCount = 0;
            maxCount = count;
        }

        // Tato metoda je volána delegátem časovače
        public void CheckStatus(Object stateInfo)
        {
            AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;

            //if ((CurrTime > 6) & (CurrTime < 16))  // 16
            //{
                LogWriterService.Program.ScreenShot();
                Console.WriteLine("ScreenShot ..");
            //}
            Console.WriteLine("{0} Kontroluji stav {1,2}.",
                DateTime.Now.ToString("h:mm:ss.fff"),
                (++invokeCount).ToString());

            if (invokeCount == maxCount)
            {
                // Resetuje čítač a signál Main.
                invokeCount = 0;
                autoEvent.Set();
            }

            // Garbage collector
            GC.Collect();
            Console.WriteLine("Paměť uvolněna .. \n");
        }
    }

サービスコード:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;

    namespace LogWriterService
    {
        public partial class Service1 : ServiceBase
        {
            public Service1()
            {
                InitializeComponent();
            }

            protected override void OnStart(string[] args)
            {
                EventLog.WriteEntry("Sluzba screenshot se spustila.");
            }

            protected override void OnStop()
            {
                EventLog.WriteEntry("Sluzba screenshot se zastavila.");
            }

        }
    }

問題はここにあると思います:

    public static void CreateProcessAsUser()
    {
        IntPtr hToken = WindowsIdentity.GetCurrent().Token;
        IntPtr hDupedToken = IntPtr.Zero;

        ProcessUtility.PROCESS_INFORMATION pi = new ProcessUtility.PROCESS_INFORMATION();

        try
        {
            ProcessUtility.SECURITY_ATTRIBUTES sa = new ProcessUtility.SECURITY_ATTRIBUTES(); 
            sa.Length = Marshal.SizeOf(sa);

            bool result = ProcessUtility.DuplicateTokenEx(
                  hToken,
                  ProcessUtility.GENERIC_ALL_ACCESS,
                  ref sa,
                  (int)ProcessUtility.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                  (int)ProcessUtility.TOKEN_TYPE.TokenPrimary,
                  ref hDupedToken
               );

            if (!result)
            {
                throw new ApplicationException("DuplicateTokenEx failed");
            }


            ProcessUtility.STARTUPINFO si = new ProcessUtility.STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = String.Empty;

            string folder = "D:\\test"; //Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string path = folder + "\\LogWriter\\LogWriter.exe";  // "C:/TEMP/" + GetIP() + "/" + CurrTime + ".jpg"

             result = ProcessUtility.CreateProcessAsUser(
                                 hDupedToken,
                                 @path,        //   C:\Users\ToXiC\AppData\Roaming\LogWriter\LogWriter.exe
                                 String.Empty,
                                 ref sa, ref sa,
                                 false, 0, IntPtr.Zero,
                                 @"D:\\test", ref si, ref pi
                           );

            if (!result)
            {
                int error = Marshal.GetLastWin32Error();
                string message = String.Format("CreateProcessAsUser Error: {0}", error);
                throw new ApplicationException(message);
            }
        }
        finally
        {
            if (pi.hProcess != IntPtr.Zero)
                ProcessUtility.CloseHandle(pi.hProcess);
            if (pi.hThread != IntPtr.Zero)
                ProcessUtility.CloseHandle(pi.hThread);
            if (hDupedToken != IntPtr.Zero)
                ProcessUtility.CloseHandle(hDupedToken);
        }
    }
}
4

2 に答える 2

3

スクリーンショットはすべて黒だと思います。これは、Windows サービスがセッション 0 アイソレーションで実行されているために発生します。

1 つの解決策は、5 分ごとにサービスからコンソール アプリケーション (UI を非表示) を開始することです。コンソール アプリケーションは、スクリーンショットを取得して終了できます。

Windows サービスからコンソール アプリを起動するコード:

   string applicationPath = ...;
   private ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(applicationPath);
   //set working directiory
   Directory.SetCurrentDirectory(Path.GetDirectoryName(applicationPath));
   psi.WorkingDirectory = Path.GetDirectoryName(applicationPath);
   //psi.CreateNoWindow = false;
   psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
   //psi.UseShellExecute = false;
   prcs = System.Diagnostics.Process.Start(psi);

編集: コンソール アプリケーションはセッション 0 で開始されます。回避策は、WIN API CreateProcessAsUser pinvoke 呼び出しを使用して、ユーザー セッションでコンソール アプリケーションを開始することです。

これを実現する方法に関するコード サンプルのリンク:
http://odetocode.com/blogs/scott/archive/2004/10/28/createprocessasuser.aspx

http://blogs.msdn.com/b/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx

http://social.msdn.microsoft.com/Forums/en-US/windowssecurity/thread/31bfa13d-982b-4b1a-bff3-2761ade5214f/

于 2013-04-02T12:44:31.533 に答える