OpenWindowStation 错误 183 /ERROR_ALREADY_EXISTS/

Posted

技术标签:

【中文标题】OpenWindowStation 错误 183 /ERROR_ALREADY_EXISTS/【英文标题】:OpenWindowStation error 183 /ERROR_ALREADY_EXISTS/ 【发布时间】:2016-07-11 15:18:46 【问题描述】:

我正在编写一个具有远程管理功能的程序,但遇到了一些问题。主要问题是,每次调用“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: 打开窗口站。信息:正在运行2 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

【问题讨论】:

您的错误报告已损坏。您不能以这种方式调用 GetLastError,因为 .net 运行时调用 Win32 API 函数。在DllImport 属性中使用SetLastError = true,然后调用Marshal.GetLastWin32Error() 谢谢,大卫!我提供了您的更正,但主要问题仍然存在! 所以,这个问题还没有决定。因此,我决定使用 ExitWindowsEx 函数(临时)来更改用户(通过注销)。 当然,这也是一个很奇怪的决定,但对于第一个版本来说已经足够了。 【参考方案1】:

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

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

只有将 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 窗口消息。

【讨论】:

谢谢你,雷米!我知道 SendSAS,但这里有几个问题: 1. 我们需要发送电子邮件给 MS 并等待他们的回复 2. 我们需要在 WinXP(32 位)上运行此代码。 @IgorEvdokimov 您不需要向 MS 发送电子邮件,事实上 SAS 电子邮件已被弃用并且不太可能回复。您只需要 Win7 SDK 中的 sas.dll 可再发行组件。 非常感谢!我想,我会在非WinXP环境下使用它!

以上是关于OpenWindowStation 错误 183 /ERROR_ALREADY_EXISTS/的主要内容,如果未能解决你的问题,请参考以下文章

Windows DuplicateHandle 命名管道句柄奇怪错误 183“文件已存在”

MySQL · 性能优化 · MySQL常见SQL错误用法

为啥我会收到错误消息:“FileExistsError: [WinError 183] 当文件已存在时无法创建文件”?

events.js:183 抛出错误; // 给 yarn build 时未处理的 'error' 事件

关于 ReadFile() WinAPI,GetLastError 抛出错误 183。在这种情况下,“ERROR_ALREADY_EXISTS”是啥意思?

我的个人项目作业错误及解决办法·