OpenWindowStation错误183 / ERROR_ALREADY_EXISTS /

时间:2016-07-11 15:18:47

标签: c# winapi winlogon

我正在编写一个具有远程管理功能的程序,我遇到了一些问题。主要问题是,每次调用'OpenWindowStation'都会导致'错误183'和空指针。

此代码作为LocalSystem帐户上的服务运行。我也试图允许桌面交互,但所有这些都是徒劳的。

我在这里回顾了几个类似的问题,但他们的决定中没有一个帮助过我。

    namespace sasserv
    {
public class sasserv : ServiceBase
{
    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern IntPtr OpenWindowStation( string name, bool fInherit, uint needAccess );

    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern IntPtr CloseWindowStation( IntPtr hWinSta );

    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern IntPtr OpenDesktop( string name, Int32 flags, bool fInherit, long param );

    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern IntPtr CloseDesktop( IntPtr hDesktop );

    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern bool PostMessage( IntPtr hWnd, UInt32 msg, UInt32 wParam, IntPtr lParam );

    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern bool SetThreadDesktop( IntPtr hDesktop );

    [DllImport("User32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern bool SetProcessWindowStation( IntPtr hWinSta );

    public const string MyServiceName = "sasserv";

    public sasserv()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        this.ServiceName = MyServiceName;
    }

    /// <summary>
    /// Start this service.
    /// </summary>
    protected override void OnStart(string[] args)
    {
        RunWinlogon();
    }

    /// <summary>
    /// Stop this service.
    /// </summary>
    protected override void OnStop()
    {
    }       

    protected void OutputLastError(string funcName) {
        int err = Marshal.GetLastWin32Error();
        if ( err > 0 )
            Out(funcName, "ERR:"+err);
    }

    private void RunWinlogon()
    {
        int WINSTA_ALL_ACCESS = 0x37F;
        long DESKTOP_CREATEMENU = 0x0004L;
        long DESKTOP_CREATEWINDOW = 0x0002L;
        long DESKTOP_ENUMERATE = 0x0040L;
        long DESKTOP_HOOKCONTROL = 0x0008L;
        long DESKTOP_JOURNALPLAYBACK = 0x0020L;
        long DESKTOP_JOURNALRECORD = 0x0010L;
        long DESKTOP_READOBJECTS = 0x0001L;
        long DESKTOP_SWITCHDESKTOP = 0x0100L;
        long DESKTOP_WRITEOBJECTS = 0x0080L;
        int HWND_BROADCAST = 0xffff;
        uint WM_HOTKEY = 0x0312;
        short MOD_ALT = 0x0001;
        short MOD_CONTROL = 0x0002;
        short VK_DELETE = 0x2E;
        uint MAXIMUM_ALLOWED = 0x2000000;

        uint WLX_WM_SAS = 0x0659;
        uint WLX_SAS_TYPE_CTRL_ALT_DEL = 0x0001;

        uint GENERIC_READ  = 0x80000000;
        uint GENERIC_WRITE  = 0x40000000;
        uint  GENERIC_EXECUTE  = 0x20000000;
        uint GENERIC_ALL  = 0x10000000;
        uint  GENERIC_RIGHTS_CHK  = 0xF0000000;

        Out("OpenWindowStation", "Running2");
        var hWinSta = OpenWindowStation( "WinSta0", false,  MAXIMUM_ALLOWED );
        if (  hWinSta == IntPtr.Zero ) {
            Out("OpenWindowStation", "hWinSta=ZERO");
            return;
        }
        OutputLastError("OpenWindowStation");


        Out("SetProcessWindowStation", "Running");
        if ( !SetProcessWindowStation( hWinSta ) ) {
            Out("SetProcessWindowStation", "FALSE");
            return;
        }

        OutputLastError("SetProcessWindowStation");

        Out("OpenDesktop", "Running");
        var hDesk = OpenDesktop( "Winlogon", 0, false, MAXIMUM_ALLOWED);

        OutputLastError("OpenDesktop");

        if ( hDesk == IntPtr.Zero ) {
            Out("OpenDesktop", "HDESK=ZERO");
            return;
        }


        if ( !SetThreadDesktop(hDesk) ) {
            Out("SetThreadDesktop", "FALSE");
            return;
        }

        OutputLastError("SetThreadDesktop");

        Out("PostMessage", "Running...");
        var postSucc = PostMessage( new IntPtr(HWND_BROADCAST),
                                   WLX_WM_SAS,
                                   WLX_SAS_TYPE_CTRL_ALT_DEL,
                                   IntPtr.Zero);

        OutputLastError("PostMessage");         

        CloseDesktop( hDesk );
        CloseWindowStation( hWinSta );          
    }

    static IntPtr MakeLongPtr( short wLow, short wHigh ) {          
        return new IntPtr( (UInt32)(wLow | ( (UInt32)wHigh << 16 )));
    }

    static void Out( string func, string info ) {
        NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        logger.Info( "FUNC: "+func+" . INFO: "+info );
    }
}
}

这是执行日志:

这是执行日志: 12.07.2016 10:29:47.3526 | sasserv | FUNC:OpenWindowStation。信息:Running2 12.07.2016 10:29:47.3646 | sasserv | FUNC:SetProcessWindowStation。信息:正在运行 12.07.2016 10:29:47.3646 | sasserv | FUNC:SetProcessWindowStation。信息:错误:183 12.07.2016 10:29:47.3746 | sasserv | FUNC:OpenDesktop。信息:正在运行 12.07.2016 10:29:47.3746 | sasserv | FUNC:OpenDesktop。信息:错误:183 12.07.2016 10:29:47.4025 | sasserv | FUNC:SetThreadDesktop。信息:错误:183 12.07.2016 10:29:47.4065 | sasserv | FUNC:PostMessage。信息:正在运行...... 12.07.2016 10:29:47.4065 | sasserv | FUNC:PostMessage。信息:错误:87

1 个答案:

答案 0 :(得分:0)

您需要将DLL导入标记为SetLastError=true,然后直接使用Marshal.GetLastWin32Error()而不是GetLastError()。来自文档:

  

GetLastWin32Error公开来自Kernel32.DLL的Win32 GetLastError函数。 此方法的存在是因为直接平台调用GetLastError来获取此信息是不安全的。如果要访问此错误代码,则必须调用GetLastWin32Error,而不是为GetLastError编写自己的平台调用定义并调用它。公共语言运行库可以对API进行内部调用,覆盖操作系统维护的GetLastError

     

只有将System.Runtime.InteropServices.DllImportAttribute应用于方法签名并将SetLastError字段设置为true,才能使用此方法获取错误代码。此过程因所使用的源语言而异:默认情况下,C#和C ++为false,但Visual Basic中的Declare语句为true。

例如:

namespace sasserv
{
    public class sasserv : ServiceBase
    {
        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern IntPtr OpenWindowStation( string name, bool fInherit, uint needAccess );

        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern IntPtr CloseWindowStation( IntPtr hWinSta );

        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern IntPtr OpenDesktop( string name, Int32 flags, bool fInherit, long param );

        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern IntPtr CloseDesktop( IntPtr hDesktop );

        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern bool PostMessage( IntPtr hWnd, UInt32 msg, UInt32 wParam, IntPtr lParam );

        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern bool SetThreadDesktop( IntPtr hDesktop );

        [DllImport("User32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        static extern bool SetProcessWindowStation( IntPtr hWinSta );

        public const string MyServiceName = "sasserv";

        public sasserv()
        {
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.ServiceName = MyServiceName;
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            // TODO: Add cleanup code here (if required)
            base.Dispose(disposing);
        }

        /// <summary>
        /// Start this service.
        /// </summary>
        protected override void OnStart(string[] args)
        {
            RunWinlogon();
        }

        /// <summary>
        /// Stop this service.
        /// </summary>
        protected override void OnStop()
        {
            // TODO: Add tear-down code here (if required) to stop your service.
        }


        protected void OutputLastError(string funcName) {
            int err = Marshal.GetLastWin32Error();
            Out(funcName, "ERR:"+err);
        }

        private void RunWinlogon()
        {
            int err = 9999;
            int WINSTA_ALL_ACCESS = 0x37F;
            long DESKTOP_CREATEMENU = 0x0004L;
            long DESKTOP_CREATEWINDOW = 0x0002L;
            long DESKTOP_ENUMERATE = 0x0040L;
            long DESKTOP_HOOKCONTROL = 0x0008L;
            long DESKTOP_JOURNALPLAYBACK = 0x0020L;
            long DESKTOP_JOURNALRECORD = 0x0010L;
            long DESKTOP_READOBJECTS = 0x0001L;
            long DESKTOP_SWITCHDESKTOP = 0x0100L;
            long DESKTOP_WRITEOBJECTS = 0x0080L;
            int HWND_BROADCAST = 0xffff;
            uint WM_HOTKEY = 0x0312;
            short MOD_ALT = 0x0001;
            short MOD_CONTROL = 0x0002;
            short VK_DELETE = 0x2E;
            uint MAXIMUM_ALLOWED = 0x2000000;

            uint WLX_WM_SAS = 0x0659;
            uint WLX_SAS_TYPE_CTRL_ALT_DEL = 0x0001;

            uint GENERIC_READ  = 0x80000000;
            uint GENERIC_WRITE  = 0x40000000;
            uint GENERIC_EXECUTE  = 0x20000000;
            uint GENERIC_ALL  = 0x10000000;
            uint GENERIC_RIGHTS_CHK  = 0xF0000000;

            Out("OpenWindowStation", "Running1");
            var hWinSta = OpenWindowStation( "WinSta0", false,  MAXIMUM_ALLOWED );
            if ( hWinSta == IntPtr.Zero ) {
                OutputLastError("OpenWindowStation");
                return;
            }

            Out("SetProcessWindowStation", "Running");
            if ( !SetProcessWindowStation( hWinSta ) ) {
                OutputLastError("SetProcessWindowStation");
                CloseWindowStation( hWinSta );          
                return;
            }

            Out("OpenDesktop", "Running");
            var hDesk = OpenDesktop( "Winlogon", 0, false, MAXIMUM_ALLOWED);

            if ( hDesk == IntPtr.Zero ) {
                OutputLastError("OpenDesktop");
                CloseWindowStation( hWinSta );          
                return;
            }

            if ( !SetThreadDesktop(hDesk) ) {
                OutputLastError("SetThreadDesktop");
                CloseDesktop( hDesk );
                CloseWindowStation( hWinSta );          
                return;
            }

            Out("PostMessage", "Running...");
            if ( !PostMessage( new IntPtr(HWND_BROADCAST),
                                       WLX_WM_SAS,
                                       WLX_SAS_TYPE_CTRL_ALT_DEL,
                                       IntPtr.Zero) ) {
                OutputLastError("PostMessage");
            }

            CloseDesktop( hDesk );
            CloseWindowStation( hWinSta );          
        }

        static IntPtr MakeLongPtr( short wLow, short wHigh ) {

            return new IntPtr( (UInt32)(wLow | ( (UInt32)wHigh << 16 )));
        }

        static void Out( string func, string info ) {
            NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

            logger.Info( "FUNC: "+func+" . "+info );
        }
    }
}

话虽这么说,发布Ctrl-Alt-Del序列的另一种方法是使用SendSAS()函数而不是广播WLX_WM_SAS窗口消息。