প্রোগ্রামযুক্তভাবে কোনও লকড ওয়ার্কস্টেশনের একটি সময়কাল নির্ধারণ করুন?


111

কেউ কীভাবে কোডটি নির্ধারণ করতে পারে, কতক্ষণ মেশিনটি লক থাকে?

সি # এর বাইরের অন্যান্য ধারণাগুলিও স্বাগত।


সরলতা এবং পরিষ্কার-পরিচ্ছন্নতার জন্য আমি উইন্ডোজ পরিষেবা আইডিয়াটি (এবং এটি স্বীকার করেছি) পছন্দ করি তবে দুর্ভাগ্যক্রমে আমি মনে করি না যে এটি এই বিশেষ ক্ষেত্রে আমার পক্ষে কাজ করবে। আমি আমার ওয়ার্কস্টেশনে এটি বাড়ির চেয়ে (বা বাড়ির পাশাপাশি, মনে করি) কাজ করে চালাতে চেয়েছিলাম, তবে এটি ডিওডি-র সৌন্দর্যে লক হয়ে গেছে। এটি আসলে আমার নিজের ঘূর্ণায়মান হওয়ার কারণ।

আমি যাইহোক এটি লিখতে এবং এটি কাজ করে কিনা দেখুন। ধন্যবাদ সবাইকে!

উত্তর:


138

আমি এটি আগে খুঁজে পাইনি, তবে কোনও অ্যাপ্লিকেশন থেকে আপনি একটি সেশনসুইচইভেন্থ হ্যান্ডলারকে হুকআপ করতে পারেন। স্পষ্টতই আপনার অ্যাপ্লিকেশনটি চলমান হওয়া দরকার, তবে এটি যতক্ষণ থাকবে:

Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch);

void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e)
{
    if (e.Reason == SessionSwitchReason.SessionLock)
    { 
        //I left my desk
    }
    else if (e.Reason == SessionSwitchReason.SessionUnlock)
    { 
        //I returned to my desk
    }
}

3
উইন্ডোজ 7 x64 এবং উইন্ডোজ 10 x64 এ 100% পরীক্ষা করা হয়েছে।
কনটাঙ্গো

বাহ, আশ্চর্যজনক কাজ করে! কোনও ত্রুটি নেই কোনও ব্যতিক্রম, মসৃণ এবং পরিষ্কার!
মায়ার স্পিৎজার

এটি করার সঠিক উপায় এটি। মাইক্রোসফ্টের এই নিবন্ধ অনুসারে , "ওয়ার্কস্টেশনটি লক রয়েছে কিনা তা নির্ধারণ করার জন্য আপনি কল করতে পারবেন এমন কোনও ফাংশন নেই।" এটি অবশ্যই সেশনসুইচইভেন্টহ্যান্ডলার ব্যবহার করে পর্যবেক্ষণ করা উচিত।
জোনাথন

35

আমি একটি উইন্ডোজ পরিষেবা তৈরি করব (একটি ভিজ্যুয়াল স্টুডিও 2005 প্রজেক্টের ধরণ) যা নিচে দেখানো অনুসারে অনসেশন চেঞ্জ ইভেন্টটি পরিচালনা করে:

protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
    if (changeDescription.Reason == SessionChangeReason.SessionLock)
    { 
        //I left my desk
    }
    else if (changeDescription.Reason == SessionChangeReason.SessionUnlock)
    { 
        //I returned to my desk
    }
}

কীভাবে আপনি কীভাবে সেই মুহুর্তে কার্যকলাপটি লগ করেন তা আপনার উপর নির্ভর করে তবে একটি উইন্ডোজ পরিষেবা লক এবং আনলক ইভেন্টগুলির পাশাপাশি উইন্ডোজ ইভেন্টগুলি স্টার্টআপ, শাটডাউন, লগইন / আউট যেমন দ্রুত এবং সহজ অ্যাক্সেস সরবরাহ করে।


18

নীচের সমাধানটি Win32 এপিআই ব্যবহার করে। ওয়ার্কস্টেশনটি লক হয়ে গেলে অনসেশনলক ডাকা হয় এবং আনলক করা অবস্থায় অনসেশনঅনলক ডাকা হয়।

[DllImport("wtsapi32.dll")]
private static extern bool WTSRegisterSessionNotification(IntPtr hWnd,
int dwFlags);

[DllImport("wtsapi32.dll")]
private static extern bool WTSUnRegisterSessionNotification(IntPtr
hWnd);

private const int NotifyForThisSession = 0; // This session only

private const int SessionChangeMessage = 0x02B1;
private const int SessionLockParam = 0x7;
private const int SessionUnlockParam = 0x8;

protected override void WndProc(ref Message m)
{
    // check for session change notifications
    if (m.Msg == SessionChangeMessage)
    {
        if (m.WParam.ToInt32() == SessionLockParam)
            OnSessionLock(); // Do something when locked
        else if (m.WParam.ToInt32() == SessionUnlockParam)
            OnSessionUnlock(); // Do something when unlocked
    }

    base.WndProc(ref m);
    return;
}

void OnSessionLock() 
{
    Debug.WriteLine("Locked...");
}

void OnSessionUnlock() 
{
    Debug.WriteLine("Unlocked...");
}

private void Form1Load(object sender, EventArgs e)
{
    WTSRegisterSessionNotification(this.Handle, NotifyForThisSession);
}

// and then when we are done, we should unregister for the notification
//  WTSUnRegisterSessionNotification(this.Handle);

1
আপনি যদি দেখতে পান যে সেশনসুইচ ইভেন্টটি (অন্যান্য উত্তরগুলি থেকে) আগুন নেভায় না (যেমন আপনার অ্যাপ্লিকেশন এটি দমন করে) This
kad81

ভবিষ্যতের পাঠকদের জন্য ... আমি মনে করি here এখানে ওভাররাইডটি সিস্টেম. উইন্ডোজ.ফর্মস.ফর্ম থেকে এসেছে, আপনি যেমন একটি ক্লাস লিখতে পারেন: পাবলিক ক্লাস
ফর্ম

এটি আমার জন্য কাজ করে যখন SystemEvents.SessionSwitch না করে
DCOPTimDowd

5

আমি জানি এটি একটি পুরানো প্রশ্ন তবে আমি একটি নির্দিষ্ট অধিবেশনটির জন্য লক স্টেট পাওয়ার জন্য একটি পদ্ধতি পেয়েছি।

আমি আমার উত্তরটি এখানে পেয়েছি তবে এটি সি ++ এ ছিল তাই আমি লক রাজ্যটি পেতে সি # তে যতটা পারি অনুবাদ করেছি translated

সুতরাং এখানে যায়:

static class SessionInfo {
    private const Int32 FALSE = 0;

    private static readonly IntPtr WTS_CURRENT_SERVER = IntPtr.Zero;

    private const Int32 WTS_SESSIONSTATE_LOCK = 0;
    private const Int32 WTS_SESSIONSTATE_UNLOCK = 1;

    private static bool _is_win7 = false;

    static SessionInfo() {
        var os_version = Environment.OSVersion;
        _is_win7 = (os_version.Platform == PlatformID.Win32NT && os_version.Version.Major == 6 && os_version.Version.Minor == 1);
    }

    [DllImport("wtsapi32.dll")]
    private static extern Int32 WTSQuerySessionInformation(
        IntPtr hServer,
        [MarshalAs(UnmanagedType.U4)] UInt32 SessionId,
        [MarshalAs(UnmanagedType.U4)] WTS_INFO_CLASS WTSInfoClass,
        out IntPtr ppBuffer,
        [MarshalAs(UnmanagedType.U4)] out UInt32 pBytesReturned
    );

    [DllImport("wtsapi32.dll")]
    private static extern void WTSFreeMemoryEx(
        WTS_TYPE_CLASS WTSTypeClass,
        IntPtr pMemory,
        UInt32 NumberOfEntries
    );

    private enum WTS_INFO_CLASS {
        WTSInitialProgram = 0,
        WTSApplicationName = 1,
        WTSWorkingDirectory = 2,
        WTSOEMId = 3,
        WTSSessionId = 4,
        WTSUserName = 5,
        WTSWinStationName = 6,
        WTSDomainName = 7,
        WTSConnectState = 8,
        WTSClientBuildNumber = 9,
        WTSClientName = 10,
        WTSClientDirectory = 11,
        WTSClientProductId = 12,
        WTSClientHardwareId = 13,
        WTSClientAddress = 14,
        WTSClientDisplay = 15,
        WTSClientProtocolType = 16,
        WTSIdleTime = 17,
        WTSLogonTime = 18,
        WTSIncomingBytes = 19,
        WTSOutgoingBytes = 20,
        WTSIncomingFrames = 21,
        WTSOutgoingFrames = 22,
        WTSClientInfo = 23,
        WTSSessionInfo = 24,
        WTSSessionInfoEx = 25,
        WTSConfigInfo = 26,
        WTSValidationInfo = 27,
        WTSSessionAddressV4 = 28,
        WTSIsRemoteSession = 29
    }

    private enum WTS_TYPE_CLASS {
        WTSTypeProcessInfoLevel0,
        WTSTypeProcessInfoLevel1,
        WTSTypeSessionInfoLevel1
    }

    public enum WTS_CONNECTSTATE_CLASS {
        WTSActive,
        WTSConnected,
        WTSConnectQuery,
        WTSShadow,
        WTSDisconnected,
        WTSIdle,
        WTSListen,
        WTSReset,
        WTSDown,
        WTSInit
    }

    public enum LockState {
        Unknown,
        Locked,
        Unlocked
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct WTSINFOEX {
        public UInt32 Level;
        public UInt32 Reserved; /* I have observed the Data field is pushed down by 4 bytes so i have added this field as padding. */
        public WTSINFOEX_LEVEL Data;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct WTSINFOEX_LEVEL {
        public WTSINFOEX_LEVEL1 WTSInfoExLevel1;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct WTSINFOEX_LEVEL1 {
        public UInt32 SessionId;
        public WTS_CONNECTSTATE_CLASS SessionState;
        public Int32 SessionFlags;

        /* I can't figure out what the rest of the struct should look like but as i don't need anything past the SessionFlags i'm not going to. */

    }

    public static LockState GetSessionLockState(UInt32 session_id) {
        IntPtr ppBuffer;
        UInt32 pBytesReturned;

        Int32 result = WTSQuerySessionInformation(
            WTS_CURRENT_SERVER,
            session_id,
            WTS_INFO_CLASS.WTSSessionInfoEx,
            out ppBuffer,
            out pBytesReturned
        );

        if (result == FALSE)
            return LockState.Unknown;

        var session_info_ex = Marshal.PtrToStructure<WTSINFOEX>(ppBuffer);

        if (session_info_ex.Level != 1)
            return LockState.Unknown;

        var lock_state = session_info_ex.Data.WTSInfoExLevel1.SessionFlags;
        WTSFreeMemoryEx(WTS_TYPE_CLASS.WTSTypeSessionInfoLevel1, ppBuffer, pBytesReturned);

        if (_is_win7) {
            /* Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ee621019(v=vs.85).aspx
                * Windows Server 2008 R2 and Windows 7:  Due to a code defect, the usage of the WTS_SESSIONSTATE_LOCK
                * and WTS_SESSIONSTATE_UNLOCK flags is reversed. That is, WTS_SESSIONSTATE_LOCK indicates that the
                * session is unlocked, and WTS_SESSIONSTATE_UNLOCK indicates the session is locked.
                * */
            switch (lock_state) {
                case WTS_SESSIONSTATE_LOCK:
                    return LockState.Unlocked;

                case WTS_SESSIONSTATE_UNLOCK:
                    return LockState.Locked;

                default:
                    return LockState.Unknown;
            }
        }
        else {
            switch (lock_state) {
                case WTS_SESSIONSTATE_LOCK:
                    return LockState.Locked;

                case WTS_SESSIONSTATE_UNLOCK:
                    return LockState.Unlocked;

                default:
                    return LockState.Unknown;
            }
        }
    }
}

দ্রষ্টব্য: উপরের কোডটি অনেক বড় প্রকল্প থেকে বের করা হয়েছিল তাই যদি আমি কিছুটা দুঃখিত অনুভব করি। আমি উপরের কোডটি পরীক্ষা করার জন্য সময় পাইনি তবে সমস্ত কিছু যাচাই করার জন্য এক-দু'সপ্তাহে ফিরে আসার পরিকল্পনা করছি। আমি এখনই এটি পোস্ট করেছি কারণ আমি এটি করতে ভুলে যেতে চাইনি।


এটি কাজ করে (উইন্ডোজ 7 এখনও পর্যন্ত পরীক্ষিত)। ধন্যবাদ, আমরা গত কয়েক সপ্তাহ ধরে এটি সন্ধান করছিলাম এবং আপনার উত্তরটি সময়ের নিকটে এসেছে!
স্টিভপ

1
কোডটিতে কয়েকটি ত্রুটি রয়েছে: ১ if (session_info_ex.Level != 1)- শর্তটি সত্য হলে, মেমরিটি মুক্তি দেওয়া হবে না। ২. যদি সেশন_ইনফো_এক্স.লভেল! = 1 আপনার এটি করা উচিত নয়: Marshal.PtrToStructure<WTSINFOEX>(ppBuffer);কারণ ফেরত বাফারের আকার ডাব্লুটিএসআইএনএফএক্স এর আকার থেকে পৃথক হতে পারে
সার্জিট

(অব্যাহত) ৩. ক্ষেত্রটি যুক্ত করার প্রয়োজন ছিল না UInt32 Reserved;পরিবর্তে আপনার কাঠামোর WTSINFOEX_LEVEL1সম্পূর্ণরূপে সংজ্ঞা দেওয়া উচিত । এই ক্ষেত্রে সংকলক কাঠামোর ভিতরে ক্ষেত্রগুলির সঠিক প্যাডিং (প্রান্তিককরণ) করবে। ৪. ফাংশন WTSFreeMemoryExএখানে অপব্যবহার করা হয়। WTSFreeMemoryপরিবর্তে ব্যবহার করা আবশ্যক। WTSFreeMemoryExপরে মেমরি বিনামূল্যে উদ্দেশ্য WTSEnumerateSessionsEx
সার্জিটি

(গণনা করা) 5. CharSet = CharSet.Autoঅবশ্যই সমস্ত বৈশিষ্ট্যে ব্যবহার করা উচিত।
সার্জিয়েট

4

আপনি যদি এই ইভেন্টগুলিকে "সন্ধান" করতে একটি উইন্ডোজ-পরিষেবা রচনায় আগ্রহী হন, টপসেল্ফ (লাইব্রেরি / ফ্রেমওয়ার্ক যা উইন্ডোজ পরিষেবাগুলি লেখার পক্ষে আরও সহজ করে তোলে) এর একটি হুক রয়েছে।

public interface IMyServiceContract
{
    void Start();

    void Stop();

    void SessionChanged(Topshelf.SessionChangedArguments args);
}



public class MyService : IMyServiceContract
{

    public void Start()
    {
    }

    public void Stop()
    {

    }

    public void SessionChanged(SessionChangedArguments e)
    {
        Console.WriteLine(e.ReasonCode);
    }   
}

এবং এখন উপরের ইন্টারফেস / কংক্রিটের মধ্যে শীর্ষস্থানীয় পরিষেবাটি তারের কোডটি

নীচে সমস্ত কিছুই "সাধারণ" টপশেল্ফ সেটআপ .... আমি 2 লাইন বাদে যা চিহ্নিত করেছি except

/ * এটি ম্যাজিক লাইন * /

সেগুলিই সেশনচ্যাঞ্জড পদ্ধতি থেকে গুলি চালায়।

আমি এটি উইন্ডোজ 10 x64 দিয়ে পরীক্ষা করেছি। আমি আমার মেশিনটিকে লক এবং আনলক করেছি এবং আমি পছন্দসই ফলাফল পেয়েছি।

            IMyServiceContract myServiceObject = new MyService(); /* container.Resolve<IMyServiceContract>(); */


            HostFactory.Run(x =>
            {
                x.Service<IMyServiceContract>(s =>
                {
                    s.ConstructUsing(name => myServiceObject);
                    s.WhenStarted(sw => sw.Start());
                    s.WhenStopped(sw => sw.Stop());
                    s.WhenSessionChanged((csm, hc, chg) => csm.SessionChanged(chg)); /* THIS IS MAGIC LINE */
                });

                x.EnableSessionChanged(); /* THIS IS MAGIC LINE */

                /* use command line variables for the below commented out properties */
                /*
                x.RunAsLocalService();
                x.SetDescription("My Description");
                x.SetDisplayName("My Display Name");
                x.SetServiceName("My Service Name");
                x.SetInstanceName("My Instance");
                */

                x.StartManually(); // Start the service manually.  This allows the identity to be tweaked before the service actually starts

                /* the below map to the "Recover" tab on the properties of the Windows Service in Control Panel */
                x.EnableServiceRecovery(r =>
                {
                    r.OnCrashOnly();
                    r.RestartService(1); ////first
                    r.RestartService(1); ////second
                    r.RestartService(1); ////subsequents
                    r.SetResetPeriod(0);
                });

                x.DependsOnEventLog(); // Windows Event Log
                x.UseLog4Net();

                x.EnableShutdown();

                x.OnException(ex =>
                {
                    /* Log the exception */
                    /* not seen, I have a log4net logger here */
                });
            });                 

সংস্করণগুলি সম্পর্কে ইঙ্গিত সরবরাহ করতে আমার প্যাকেজ.কনফিগ

  <package id="log4net" version="2.0.5" targetFramework="net45" />
  <package id="Topshelf" version="4.0.3" targetFramework="net461" />
  <package id="Topshelf.Log4Net" version="4.0.3" targetFramework="net461" />

অথবা আপনি যদি প্রয়োগ করে থাকেন এবং পরিষেবা শ্রেণীর উদাহরণের অন্তর্নিহিততা তৈরি না করেন তবে ইন্টারফেস প্রয়োগের x.EnableSessionChanged();সাথে একযোগে ব্যবহার করা সম্ভব । লাইক । আপনাকে প্রয়োগ আছে এর মধ্যে শ্রেণী:ServiceSessionChangeServiceControlx.Service<ServiceImpl>();ServiceSessionChangeServiceImplclass ServiceImpl : ServiceControl, ServiceSessionChange
oleksa

3

দ্রষ্টব্য : এটি কোনও উত্তর নয়, তবে টিমোথি কার্টারের উত্তরটির জন্য একটি (অবদান) , কারণ আমার খ্যাতি আমাকে এ পর্যন্ত মন্তব্য করতে দেয় না।

টিমোথিয়া কার্টারের উত্তর থেকে যদি কেউ কোডটি চেষ্টা করে এবং এখনই এটি উইন্ডোজ পরিষেবাতে কাজ করার সুযোগ না পেয়ে থাকে, সে ক্ষেত্রে একটি সম্পত্তি রয়েছে যা পরিষেবাটির নির্মাতাকে সেট করতে হবে true। কেবল কনস্ট্রাক্টরে লাইন যুক্ত করুন:

CanHandleSessionChangeEvent = true;

এবং পরিষেবাটি শুরু হওয়ার পরে এই সম্পত্তিটি সেট না করার বিষয়ে নিশ্চিত হন অন্যথায় একটি InvalidOperationExceptionনিক্ষিপ্ত হবে।


-3

নীচে পিসি লক হয়েছে কিনা তা অনুসন্ধানের জন্য 100% কার্যকারী কোড রয়েছে।

এটি ব্যবহারের আগে নেমস্পেস ব্যবহার করুন System.Runtime.InteropServices

[DllImport("user32", EntryPoint = "OpenDesktopA", CharSet = CharSet.Ansi,SetLastError = true, ExactSpelling = true)]
private static extern Int32 OpenDesktop(string lpszDesktop, Int32 dwFlags, bool fInherit, Int32 dwDesiredAccess);

[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern Int32 CloseDesktop(Int32 hDesktop);

[DllImport("user32", CharSet = CharSet.Ansi,SetLastError = true,ExactSpelling = true)]
private static extern Int32 SwitchDesktop(Int32 hDesktop);

public static bool IsWorkstationLocked()
{
    const int DESKTOP_SWITCHDESKTOP = 256;
    int hwnd = -1;
    int rtn = -1;

    hwnd = OpenDesktop("Default", 0, false, DESKTOP_SWITCHDESKTOP);

    if (hwnd != 0)
    {
        rtn = SwitchDesktop(hwnd);
        if (rtn == 0)
        {
            // Locked
            CloseDesktop(hwnd);
            return true;
        }
        else
        {
            // Not locked
            CloseDesktop(hwnd);
        }
    }
    else
    {
        // Error: "Could not access the desktop..."
    }

    return false;
}

4
পরিবর্তে সক্রিয় ডেস্কটপের নাম পেতে ওপেনইনপুটডেস্কটপ এবং গেটউজারঅবজেক্টআইফর্মেশনের জন্য এমএসডিএন পরীক্ষা করে দেখুন। মাইক্রোসফ্ট থেকে ডেস্কটপ.এক্সই ইউটিলিটি ব্যবহার করে, একাধিক ডেস্কটপগুলিতে কাজ করা ব্যবহারকারীদের জন্য উপরের কোডটি নিরাপদ / সুন্দর নয়। বা আরও ভাল, কেবল সক্রিয় ডেস্কটপে (সেটট্রেডডেস্কটপ) একটি উইন্ডো তৈরি করার চেষ্টা করুন এবং যদি এটি কাজ করে তবে এটিতে আপনার ইউআইটি দেখান। যদি তা না হয় তবে এটি একটি সুরক্ষিত / বিশেষ ডেস্কটপ, তাই করবেন না।
eselk
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.