我正在编写一个具有远程管理功能的程序,但我仍然遇到了一些问题。主要问题是,每次调用“OpenWindowStation”都会导致'error 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。信息:错误:18312.07.2016 10:29:47.3746\sasserv\FUNC: OpenDesktop。信息:运行12.07.2016 10:29:47.3746\sasserv\FUNC: OpenDesktop。信息:错误:18312.07.2016 10:29:47.4025\sasserv\FUNC: SetThreadDesktop。信息:错误:18312.07.2016 10:29:47.4065\sasserv\FUNC: PostMessage。信息:跑步..。2016年7月12日10时29分:47.4065分: PostMessage。信息:错误:87
发布于 2016-07-11 18:06:42
您需要将DLL导入标记为SetLastError=true,然后直接使用Marshal.GetLastWin32Error()而不是GetLastError()。从文件中:
GetLastErrorGetLastWin32Error公开了Kernel32.DLL中的Win32GetLastError函数,之所以存在,是因为不安全地直接调用来获取信息。如果要访问此错误代码,则必须调用GetLastWin32Error,而不是为GetLastError编写自己的平台调用定义并调用它。公共语言运行库可以对覆盖操作系统维护的GetLastError的API进行内部调用。 只有将System.Runtime.InteropServices.DllImportAttribute应用于方法签名并将SetLastError字段设置为true时,才能使用此方法获取错误代码。根据所使用的源语言,此过程不同:默认情况下,C#和C++为false,但Visual中的声明语句为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序列的另一种方法是使用SendSAS()函数,而不是广播WLX_WM_SAS窗口消息。
https://stackoverflow.com/questions/38310564
复制相似问题