c विंडोज़ सेवा से स्क्रीनशॉट कैप्चर करने का कार्यक्रम निष्पादित करें



windows service (1)

इसके लिए अलीस्टैड ने सभी भारी लिफ्टिंग की। उसके कोड पर एक नज़र डालें, यह एक शानदार शुरुआत है। ध्यान रखें, आपको स्क्रीनशॉट लेने के लिए एक अलग ऐप की आवश्यकता होगी क्योंकि लॉग इन करते समय एक नई प्रक्रिया को लॉग इन करते हुए उपयोगकर्ता को बंद करना होगा। https://stackoverflow.com/a/4147868/125406

यहाँ इसका मेरा संस्करण है (पूरी तरह से अलीस्टैड के कोड पर आधारित)। यह कमांड लाइन परमेस को जोड़ता है, प्रक्रिया से बाहर निकलने और कोड वापस करने के लिए प्रतीक्षा करता है।

public static class ProcessAsCurrentUser
{

    /// <summary>
    /// Connection state of a session.
    /// </summary>
    public enum ConnectionState
    {
        /// <summary>
        /// A user is logged on to the session.
        /// </summary>
        Active,

        /// <summary>
        /// A client is connected to the session.
        /// </summary>
        Connected,

        /// <summary>
        /// The session is in the process of connecting to a client.
        /// </summary>
        ConnectQuery,

        /// <summary>
        /// This session is shadowing another session.
        /// </summary>
        Shadowing,

        /// <summary>
        /// The session is active, but the client has disconnected from it.
        /// </summary>
        Disconnected,

        /// <summary>
        /// The session is waiting for a client to connect.
        /// </summary>
        Idle,

        /// <summary>
        /// The session is listening for connections.
        /// </summary>
        Listening,

        /// <summary>
        /// The session is being reset.
        /// </summary>
        Reset,

        /// <summary>
        /// The session is down due to an error.
        /// </summary>
        Down,

        /// <summary>
        /// The session is initializing.
        /// </summary>
        Initializing
    }


    [StructLayout(LayoutKind.Sequential)]
    class SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct STARTUPINFO
    {
        public Int32 cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    enum LOGON_TYPE
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK,
        LOGON32_LOGON_BATCH,
        LOGON32_LOGON_SERVICE,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT,
        LOGON32_LOGON_NEW_CREDENTIALS
    }

    enum LOGON_PROVIDER
    {
        LOGON32_PROVIDER_DEFAULT,
        LOGON32_PROVIDER_WINNT35,
        LOGON32_PROVIDER_WINNT40,
        LOGON32_PROVIDER_WINNT50
    }

    [Flags]
    enum CreateProcessFlags : uint
    {
        CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
        CREATE_DEFAULT_ERROR_MODE = 0x04000000,
        CREATE_NEW_CONSOLE = 0x00000010,
        CREATE_NEW_PROCESS_GROUP = 0x00000200,
        CREATE_NO_WINDOW = 0x08000000,
        CREATE_PROTECTED_PROCESS = 0x00040000,
        CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
        CREATE_SEPARATE_WOW_VDM = 0x00000800,
        CREATE_SHARED_WOW_VDM = 0x00001000,
        CREATE_SUSPENDED = 0x00000004,
        CREATE_UNICODE_ENVIRONMENT = 0x00000400,
        DEBUG_ONLY_THIS_PROCESS = 0x00000002,
        DEBUG_PROCESS = 0x00000001,
        DETACHED_PROCESS = 0x00000008,
        EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
        INHERIT_PARENT_AFFINITY = 0x00010000
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct WTS_SESSION_INFO
    {
        public int SessionID;
        [MarshalAs(UnmanagedType.LPTStr)] public string WinStationName;
        public ConnectionState State;
    }

    [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Int32 WTSEnumerateSessions(IntPtr hServer, int reserved, int version,
        ref IntPtr sessionInfo, ref int count);


    [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUserW", SetLastError = true, CharSet = CharSet.Auto)]
    static extern bool CreateProcessAsUser(
        IntPtr hToken,
        string lpApplicationName,
        string lpCommandLine,
        IntPtr lpProcessAttributes,
        IntPtr lpThreadAttributes,
        bool bInheritHandles,
        UInt32 dwCreationFlags,
        IntPtr lpEnvironment,
        string lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern Int32 WaitForSingleObject(IntPtr handle, Int32 wait);

    public const Int32 INFINITE = -1;
    public const Int32 WAIT_ABANDONED = 0x80;
    public const Int32 WAIT_OBJECT_0 = 0x00;
    public const Int32 WAIT_TIMEOUT = 0x102;
    public const Int32 WAIT_FAILED = -1;

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool GetExitCodeProcess(IntPtr hProcess, out uint exitCode);

    [DllImport("wtsapi32.dll")]
    public static extern void WTSFreeMemory(IntPtr memory);

    [DllImport("kernel32.dll")]
    private static extern UInt32 WTSGetActiveConsoleSessionId();

    [DllImport("wtsapi32.dll", SetLastError = true)]
    static extern int WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateTokenEx(
        IntPtr hExistingToken,
        uint dwDesiredAccess,
        IntPtr lpTokenAttributes,
        int ImpersonationLevel,
        int TokenType,
        out IntPtr phNewToken);

    private const int TokenImpersonation = 2;
    private const int SecurityIdentification = 1;
    private const int MAXIMUM_ALLOWED = 0x2000000;
    private const int TOKEN_DUPLICATE = 0x2;
    private const int TOKEN_QUERY = 0x00000008;

    /// <summary>
    /// Launches a process for the current logged on user if there are any.
    /// If none, return false as well as in case of 
    /// 
    /// ##### !!! BEWARE !!! ####  ------------------------------------------
    /// This code will only work when running in a windows service (where it is really needed)
    /// so in case you need to test it, it needs to run in the service. Reason
    /// is a security privileg which only services have (SE_??? something, cant remember)!
    /// </summary>
    /// <param name="processExe"></param>
    /// <returns></returns>
    public static uint CreateProcessAsCurrentUser(string processExe, string commandLine)
    {

        IntPtr duplicate = new IntPtr();
        STARTUPINFO info = new STARTUPINFO();
        PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION();

        Debug.WriteLine(string.Format("CreateProcessAsCurrentUser. processExe: " + processExe));

        IntPtr p = GetCurrentUserToken();

        bool result = DuplicateTokenEx(p, MAXIMUM_ALLOWED | TOKEN_QUERY | TOKEN_DUPLICATE, IntPtr.Zero,
            SecurityIdentification, SecurityIdentification, out duplicate);
        Debug.WriteLine(string.Format("DuplicateTokenEx result: {0}", result));
        Debug.WriteLine(string.Format("duplicate: {0}", duplicate));


        if (result)
        {
            //NOTE: CREATE_NO_WINDOW will hide the console 
            //If there are commandline options, pass them AND the exe in 
            //commandLine and leave processExe empty.
            result = CreateProcessAsUser(duplicate, processExe, commandLine,
                //                    IntPtr.Zero, IntPtr.Zero, false, (UInt32) CreateProcessFlags.CREATE_NEW_CONSOLE, IntPtr.Zero, null,
                IntPtr.Zero, IntPtr.Zero, false, (UInt32)CreateProcessFlags.CREATE_NO_WINDOW, IntPtr.Zero, null,
                ref info, out procInfo);
            Debug.WriteLine(string.Format("CreateProcessAsUser result: {0}", result));

        }


        if (p.ToInt32() != 0)
        {
            Marshal.Release(p);
            Debug.WriteLine(string.Format("Released handle p: {0}", p));
        }


        if (duplicate.ToInt32() != 0)
        {
            Marshal.Release(duplicate);
            Debug.WriteLine(string.Format("Released handle duplicate: {0}", duplicate));
        }

        //Wait for the process to complete
        WaitForSingleObject(procInfo.hProcess, (int)INFINITE);

        //Get and return the exit code
        uint exitcode;
        GetExitCodeProcess(procInfo.hProcess, out exitcode);

        return exitcode;
    }

    public static int GetCurrentSessionId()
    {
        uint sessionId = WTSGetActiveConsoleSessionId();
        Debug.WriteLine(string.Format("sessionId: {0}", sessionId));

        if (sessionId == 0xFFFFFFFF)
            return -1;
        else
            return (int)sessionId;
    }

    public static bool IsUserLoggedOn()
    {
        List<WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
        Debug.WriteLine(string.Format("Number of sessions: {0}", wtsSessionInfos.Count));
        int activeSessionCount = 0;
        foreach (var session in wtsSessionInfos)
        {
            if (session.State == ConnectionState.Active)
                activeSessionCount++;
        }
        //return wtsSessionInfos.Where(x => x.State == ConnectionState.Active).Count() > 0;
        return activeSessionCount > 0;
    }

    private static IntPtr GetCurrentUserToken()
    {
        List<WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
        int sessionId = 0;
        foreach (var session in wtsSessionInfos)
        {
            if (session.State == ConnectionState.Active)
            {
                sessionId = session.SessionID;
                break;
            }
        }
        //Old Linq method
        //int sessionId = wtsSessionInfos.Where(x => x.State == ConnectionState.Active).FirstOrDefault().SessionID;
        //int sessionId = GetCurrentSessionId();

        Debug.WriteLine(string.Format("sessionId: {0}", sessionId));
        if (sessionId == int.MaxValue)
        {
            return IntPtr.Zero;
        }
        else
        {
            IntPtr p = new IntPtr();
            int result = WTSQueryUserToken((UInt32)sessionId, out p);
            Debug.WriteLine(string.Format("WTSQueryUserToken result: {0}", result));
            Debug.WriteLine(string.Format("WTSQueryUserToken p: {0}", p));

            return p;
        }
    }

    public static List<WTS_SESSION_INFO> ListSessions()
    {
        IntPtr server = IntPtr.Zero;
        List<WTS_SESSION_INFO> ret = new List<WTS_SESSION_INFO>();

        try
        {
            IntPtr ppSessionInfo = IntPtr.Zero;

            Int32 count = 0;
            Int32 retval = WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref ppSessionInfo, ref count);
            Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));

            Int64 current = (int)ppSessionInfo;

            if (retval != 0)
            {
                for (int i = 0; i < count; i++)
                {
                    WTS_SESSION_INFO si =
                        (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current,
                            typeof(WTS_SESSION_INFO));
                    current += dataSize;

                    ret.Add(si);
                }

                WTSFreeMemory(ppSessionInfo);
            }
        }
        catch (Exception exception)
        {
            Debug.WriteLine(exception.ToString());
        }

        return ret;
    }

}

हम स्क्रीनशॉट ऐप के पैरामीटर के रूप में एक फ़ाइलनाम पास करते हैं और फिर इसके पूरा होने की प्रतीक्षा करते हैं। सेवा तब फ़ाइल को चुनती है और संसाधित करती है और उसे हटा देती है।

नामांकित पाइपों का उपयोग करके हमने इसके चारों ओर एक और रास्ता भी खोज लिया। मैं उस समाधान से कम परिचित हूं।

https://code.i-harness.com

मैं एक विंडोज़ सेवा लिख ​​रहा हूं, जो स्क्रीनशॉट को कैप्चर करने वाले कुछ एजेंट प्रोग्राम को प्रबंधित करेगा। एजेंट प्रोग्राम ठीक काम करता है, कोई समस्या नहीं है - यह सिर्फ स्क्रीनशॉट लेता है और इसे bmp फ़ाइल में सहेजता है। लेकिन जब मैं इस एजेंट प्रोग्राम को अपनी सेवा से निष्पादित करने का प्रयास करता हूं - यह काम नहीं करता है, तो मुझे सभी ब्लैक पिक्चर्स मिलते हैं (जैसे कि अगर मैं सीधे स्क्रीनशॉट को अपनी सेवा से कैप्चर करने की कोशिश करता हूं) मेरी सेवा के अंदर मेरा कोड है:

ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);

SHELLEXECUTEINFO seInfo;
seInfo.cbSize = sizeof(SHELLEXECUTEINFO);
seInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
seInfo.hwnd = NULL;
seInfo.lpVerb = TEXT("open");
seInfo.lpFile = TEXT("D:\\dev\\work\\agent.exe");
seInfo.lpDirectory = TEXT("D:\\dev\\work\\");
seInfo.nShow = SW_SHOWNORMAL;
seInfo.hInstApp = NULL;

ShellExecuteEx(&seInfo);

मैंने सेवा गुणों को बदलने की कोशिश की - डेस्कटॉप के साथ बातचीत करने की अनुमति देने के लिए, सिस्टम से सेवा उपयोगकर्ता को अपने स्थानीय खाते में बदलने के लिए - कुछ भी मदद नहीं करता। मैं इसे उचित रूप से काम करने के लिए क्या कर सकता हूं?

युपीडी। ठीक है, मुझे लगता है, यह इसलिए होता है क्योंकि मेरी सेवा सत्र0 में कार्यक्रम निष्पादित करती है। मैं CreateProcess() और CreateProcessAsUser() रूप में अच्छी तरह से - कोई परिणाम नहीं की कोशिश की। तो मैं सत्र 201 में कैसे नहीं बना सकता हूँ?





service