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 公开 Win32GetLastError
函数。 存在此方法是因为直接平台调用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“文件已存在”
为啥我会收到错误消息:“FileExistsError: [WinError 183] 当文件已存在时无法创建文件”?
events.js:183 抛出错误; // 给 yarn build 时未处理的 'error' 事件
关于 ReadFile() WinAPI,GetLastError 抛出错误 183。在这种情况下,“ERROR_ALREADY_EXISTS”是啥意思?