我正在编写一个具有远程管理功能的程序,我遇到了一些问题。主要问题是,每次调用'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
答案 0 :(得分:0)
您需要将DLL导入标记为SetLastError=true
,然后直接使用Marshal.GetLastWin32Error()
而不是GetLastError()
。来自文档:
GetLastWin32Error
公开来自Kernel32.DLL的Win32GetLastError
函数。 此方法的存在是因为直接平台调用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
窗口消息。