187 lines
4.5 KiB
C++
187 lines
4.5 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
||
|
//
|
||
|
// File: schedlog.c
|
||
|
//
|
||
|
// Contents: Task Scheduler StartShell notification
|
||
|
//
|
||
|
// Classes: None.
|
||
|
//
|
||
|
// Functions:
|
||
|
// SchedStartShell - queue the work to the WinLogon thread pool.
|
||
|
// DoSchedStartShell - notify Sched service that a user logged on.
|
||
|
//
|
||
|
// History: 07-Mar-01 JBenton Created
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Note: We don't build/publish a lib here as suggested in wlnotify.cxx.
|
||
|
// Rather we include the source file here because there is only a single
|
||
|
// simple function.
|
||
|
//
|
||
|
// Note: We are using the StartShell event because the Scheduler service
|
||
|
// expects the user's explorer session to be running.
|
||
|
//
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <winwlx.h>
|
||
|
|
||
|
#define SCHED_SERVICE_NAME TEXT("Schedule")
|
||
|
|
||
|
//
|
||
|
// The following LOGON and LOGOFF defines must be kept in sync with
|
||
|
// the definition in %sdxroot%\admin\services\sched\inc\common.hxx
|
||
|
//
|
||
|
#define SERVICE_CONTROL_USER_LOGON 128
|
||
|
#define SERVICE_CONTROL_USER_LOGOFF 133
|
||
|
|
||
|
DWORD WINAPI SchedStartShell(LPVOID lpvParam);
|
||
|
DWORD WINAPI DoSchedStartShell(LPVOID lpvParam);
|
||
|
|
||
|
DWORD WINAPI
|
||
|
SchedEventLogOff(LPVOID lpvParam)
|
||
|
//
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// Send a logoff notification to the Task Scheduler service
|
||
|
// via a user defined Service Control.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// lpvParam - Winlogon notification info (unused as of yet)
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// Extended error status from Service control functions.
|
||
|
//
|
||
|
{
|
||
|
DWORD status = ERROR_SUCCESS;
|
||
|
SC_HANDLE hSC = NULL;
|
||
|
SC_HANDLE hSvc = NULL;
|
||
|
BOOL bSucceeded = FALSE;
|
||
|
SERVICE_STATUS ServiceStatus;
|
||
|
|
||
|
hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
||
|
if (hSC == NULL)
|
||
|
{
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
hSvc = OpenService(hSC, SCHED_SERVICE_NAME,
|
||
|
SERVICE_USER_DEFINED_CONTROL);
|
||
|
if (hSvc == NULL)
|
||
|
{
|
||
|
CloseServiceHandle(hSC);
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
bSucceeded = ControlService(hSvc,
|
||
|
SERVICE_CONTROL_USER_LOGOFF,
|
||
|
&ServiceStatus);
|
||
|
if( !bSucceeded )
|
||
|
{
|
||
|
status = GetLastError();
|
||
|
}
|
||
|
|
||
|
CloseServiceHandle(hSvc);
|
||
|
CloseServiceHandle(hSC);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
DWORD WINAPI
|
||
|
SchedStartShell(LPVOID lpvParam)
|
||
|
|
||
|
{
|
||
|
DWORD dwSessionId = 0;
|
||
|
|
||
|
//
|
||
|
// Don't send logon notification to Terminal Server sessions.
|
||
|
//
|
||
|
if (ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId) &&
|
||
|
(dwSessionId == 0))
|
||
|
{
|
||
|
//
|
||
|
// Queue the work to the thread pool since we may
|
||
|
// be looping on the notification.
|
||
|
//
|
||
|
QueueUserWorkItem(DoSchedStartShell, lpvParam, WT_EXECUTELONGFUNCTION);
|
||
|
}
|
||
|
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
DWORD WINAPI
|
||
|
DoSchedStartShell(LPVOID lpvParam)
|
||
|
//
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// Send a logon notification to the Task Scheduler service
|
||
|
// via a user defined Service Control.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// lpvParam - Winlogon notification info (unused as of yet)
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// Extended error status from Service control functions.
|
||
|
//
|
||
|
{
|
||
|
DWORD status = ERROR_SUCCESS;
|
||
|
PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
|
||
|
|
||
|
SC_HANDLE hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
||
|
if (hSC == NULL)
|
||
|
{
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
SC_HANDLE hSvc = OpenService(hSC, SCHED_SERVICE_NAME,
|
||
|
SERVICE_USER_DEFINED_CONTROL);
|
||
|
if (hSvc == NULL)
|
||
|
{
|
||
|
CloseServiceHandle(hSC);
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
BOOL fSucceeded;
|
||
|
const int NOTIFY_RETRIES = 20;
|
||
|
const DWORD NOTIFY_SLEEP = 4000;
|
||
|
|
||
|
//
|
||
|
// Use a retry loop to notify the service. This is done
|
||
|
// because, if the user logs in quickly, the service may not
|
||
|
// be started when the shell runs this instance.
|
||
|
//
|
||
|
for (int i = 1; ; i++)
|
||
|
{
|
||
|
SERVICE_STATUS Status;
|
||
|
fSucceeded = ControlService(hSvc,
|
||
|
SERVICE_CONTROL_USER_LOGON,
|
||
|
&Status);
|
||
|
if (fSucceeded)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i >= NOTIFY_RETRIES)
|
||
|
{
|
||
|
status = GetLastError();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Sleep(NOTIFY_SLEEP);
|
||
|
}
|
||
|
|
||
|
CloseServiceHandle(hSvc);
|
||
|
CloseServiceHandle(hSC);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|