|
|
/*++
Copyright (c) 2000 Microsoft Corporation. All rights reserved.
Module Name: tabsrv.cpp
Abstract: This is the main module of the Tablet PC Listener service.
Author: Michael Tsang (MikeTs) 01-Jun-2000
Environment: User mode
Revision History: --*/
#ifndef INITGUID
#define INITGUID
#endif
#include "pch.h"
#include <userenv.h>
extern "C" { HANDLE GetCurrentUserTokenW(WCHAR Winsta[], DWORD DesiredAccess); };
//
// Global data
//
HMODULE ghMod = NULL; DWORD gdwfTabSrv = 0; LIST_ENTRY glistNotifyClients = {0}; HANDLE ghDesktopSwitchEvent = NULL; HANDLE ghmutNotifyList = NULL; HANDLE ghHotkeyEvent = NULL; HANDLE ghRefreshEvent = NULL; HANDLE ghRPCServerThread = NULL; HWND ghwndSuperTIP = NULL; HWND ghwndMouse = NULL; HWND ghwndSuperTIPInk = NULL; HCURSOR ghcurPressHold = NULL; HCURSOR ghcurNormal = NULL; UINT guimsgSuperTIPInk = 0; #ifdef DRAW_INK
HWND ghwndDrawInk = NULL; #endif
ISuperTip *gpISuperTip = NULL; ITellMe *gpITellMe = NULL; int gcxScreen = 0, gcyScreen = 0; int gcxPrimary = 0, gcyPrimary = 0; LONG glVirtualDesktopLeft = 0, glVirtualDesktopRight = 0, glVirtualDesktopTop = 0, glVirtualDesktopBottom = 0; LONG glLongOffset = 0, glShortOffset = 0; int giButtonsSwapped = 0; ULONG gdwMinX = 0, gdwMaxX = MAX_NORMALIZED_X, gdwRngX = MAX_NORMALIZED_X; ULONG gdwMinY = 0, gdwMaxY = MAX_NORMALIZED_Y, gdwRngY = MAX_NORMALIZED_Y; int gixIndex = 0, giyIndex = 0; INPUT gInput = {INPUT_MOUSE}; DWORD gdwPenState = PENSTATE_NORMAL; DWORD gdwPenDownTime = 0; LONG glPenDownX = 0; LONG glPenDownY = 0; DWORD gdwPenUpTime = 0; LONG glPenUpX = 0; LONG glPenUpY = 0; WORD gwLastButtons = 0; CONFIG gConfig = {0}; GESTURE_SETTINGS gDefGestureSettings = { sizeof(GESTURE_SETTINGS), GESTURE_FEATURE_RECOG_ENABLED | GESTURE_FEATURE_PRESSHOLD_ENABLED, 200, //iRadius
6, //iMinOutPts
800, //iMaxTimeToInspect
3, //iAspectRatio
400, //iCheckTime
4, //iPointsToExamine
50, //iStopDist
350, //iStopTime (was 200)
500, //iPressHoldTime
3, //iHoldTolerance
700, //iCancelPressHoldTime
PopupSuperTIP, PopupMIP, GestureNoAction, GestureNoAction }; BUTTON_SETTINGS gDefButtonSettings = { sizeof(BUTTON_SETTINGS), Enter, PageUp, InvokeNoteBook, AltEsc, PageDown, BUTTONSTATE_DEFHOTKEY }; TSTHREAD gTabSrvThreads[] = { RPCServerThread, "RPCServer", TSF_RPCTHREAD, THREADF_ENABLED, 0, NULL, NULL, -1, NULL, SuperTIPThread, "SuperTIP", TSF_SUPERTIPTHREAD, THREADF_ENABLED | THREADF_SDT_POSTMSG | THREADF_RESTARTABLE, 0, NULL, NULL, -1, NULL, DeviceThread, "Digitizer", TSF_DIGITHREAD, THREADF_ENABLED | THREADF_SDT_SETEVENT | THREADF_RESTARTABLE, 0, NULL, NULL, -1, (PVOID)&gdevDigitizer, #ifdef MOUSE_THREAD
MouseThread, "Mouse", TSF_MOUSETHREAD, THREADF_ENABLED | THREADF_SDT_POSTMSG | THREADF_RESTARTABLE, 0, NULL, NULL, -1, NULL, #endif
DeviceThread, "Buttons", TSF_BUTTONTHREAD, THREADF_ENABLED | THREADF_SDT_SETEVENT | THREADF_RESTARTABLE, 0, NULL, NULL, -1, (PVOID)&gdevButtons, }; #define NUM_THREADS ARRAYSIZE(gTabSrvThreads)
TCHAR gtszTabSrvTitle[128] = {0}; TCHAR gtszTabSrvName[] = TEXT(STR_TABSRV_NAME); TCHAR gtszGestureSettings[] = TEXT("GestureSettings"); TCHAR gtszButtonSettings[] = TEXT("ButtonSettings"); TCHAR gtszPenTilt[] = TEXT("PenTilt"); TCHAR gtszLinearityMap[] = TEXT(STR_LINEARITY_MAP); TCHAR gtszRegPath[] = TEXT(STR_REGPATH_TABSRVPARAM); TCHAR gtszPortraitMode2[] = TEXT("PortraitMode2"); TCHAR gtszInputDesktop[32] = {0};
SERVICE_STATUS_HANDLE ghServStatus = NULL; SERVICE_STATUS gServStatus = {0}; DIGITIZER_DATA gLastRawDigiReport = {0}; DEVICE_DATA gdevDigitizer = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_PEN}; DEVICE_DATA gdevButtons = {HID_USAGE_PAGE_CONSUMER, HID_USAGE_CONSUMERCTRL};
#ifdef DEBUG
NAMETABLE ServiceControlNames[] = { SERVICE_CONTROL_STOP, "Stop", SERVICE_CONTROL_PAUSE, "Pause", SERVICE_CONTROL_CONTINUE, "Continue", SERVICE_CONTROL_INTERROGATE, "Interrogate", SERVICE_CONTROL_SHUTDOWN, "Shutdown", SERVICE_CONTROL_PARAMCHANGE, "ParamChange", SERVICE_CONTROL_NETBINDADD, "NetBindAdd", SERVICE_CONTROL_NETBINDREMOVE, "NetBindRemove", SERVICE_CONTROL_NETBINDENABLE, "NetBindEnable", SERVICE_CONTROL_NETBINDDISABLE, "NetBindDisable", 0, NULL }; NAMETABLE ConsoleControlNames[] = { CTRL_C_EVENT, "CtrlCEvent", CTRL_BREAK_EVENT, "CtrlBreakEvent", CTRL_CLOSE_EVENT, "CloseEvent", CTRL_LOGOFF_EVENT, "LogOffEvent", CTRL_SHUTDOWN_EVENT, "ShutDownEvent", 0, NULL }; #endif
/*++
@doc EXTERNAL
@func int | main | Program entry point.
@parm IN int | icArgs | Specifies number of command line arguments. @parm IN PSZ * | apszArgs | Points to the array of argument strings.
@rvalue SUCCESS | Returns 0. @rvalue FAILURE | Returns -1. --*/
int __cdecl main( IN int icArgs, IN LPTSTR *aptszArgs ) { TRACEPROC("main", 1) int rc = 0;
TRACEINIT(STR_TABSRV_NAME, 0, 0); TRACEENTER(("(icArgs=%d,aptszArgs=%p)\n", icArgs, aptszArgs));
ghMod = GetModuleHandle(NULL); TRACEASSERT(ghMod != NULL); LoadString(ghMod, IDS_TABSRV_TITLE, gtszTabSrvTitle, ARRAYSIZE(gtszTabSrvTitle));
if (icArgs == 1) { //
// No command line argument, must be SCM...
//
SERVICE_TABLE_ENTRY ServiceTable[] = { {gtszTabSrvName, TabSrvMain}, {NULL, NULL} };
if (!StartServiceCtrlDispatcher(ServiceTable)) { TABSRVERR(("Failed to start service dispatcher (err=%d).\n", GetLastError())); rc = -1; } } else if (icArgs == 2) { if ((aptszArgs[1][0] == TEXT('-')) || (aptszArgs[1][0] == TEXT('/'))) { if (lstrcmpi(&aptszArgs[1][1], TEXT("install")) == 0) { InstallTabSrv(); } #ifdef ALLOW_REMOVE
else if (lstrcmpi(&aptszArgs[1][1], TEXT("remove")) == 0) { RemoveTabSrv(); } #endif
#ifdef ALLOW_START
else if (lstrcmpi(&aptszArgs[1][1], TEXT("start")) == 0) { StartTabSrv(); } #endif
#ifdef ALLOW_STOP
else if (lstrcmpi(&aptszArgs[1][1], TEXT("stop")) == 0) { StopTabSrv(); } #endif
#ifdef ALLOW_DEBUG
else if (lstrcmpi(&aptszArgs[1][1], TEXT("debug")) == 0) { gdwfTabSrv |= TSF_DEBUG_MODE; SetConsoleCtrlHandler(TabSrvConsoleHandler, TRUE); TabSrvMain(0, NULL); } #endif
else { TABSRVERR(("Invalid command line argument \"%s\".\n", aptszArgs[1])); rc = -1; } } else { TABSRVERR(("Invalid command line syntax \"%s\".\n", aptszArgs[1])); rc = -1; } } else { TABSRVERR(("Too many command line arguments.\n")); rc = -1; }
TRACEEXIT(("=%d\n", rc)); TRACETERMINATE(); return rc; } //main
/*++
@doc INTERNAL
@func VOID | InstallTabSrv | Install TabSrv service.
@parm None.
@rvalue None. --*/
VOID InstallTabSrv( VOID ) { TRACEPROC("InstallTabSrv", 2) SC_HANDLE hSCM; SC_HANDLE hService;
TRACEENTER(("()\n"));
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); TRACEASSERT(hSCM != NULL);
hService = CreateService(hSCM, gtszTabSrvName, gtszTabSrvTitle, SERVICE_ALL_ACCESS | SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, TEXT("%SystemRoot%\\system32\\tabsrv.exe"), NULL, NULL, NULL, NULL, NULL);
if (hService != NULL) { SetTabSrvConfig(hService); CloseServiceHandle(hService); } else { TABSRVERR(("Failed to create TabSrv service (err=%d).\n", GetLastError())); }
CloseServiceHandle(hSCM);
//
// Go ahead and start the service for no-reboot install.
//
StartTabSrv();
TRACEEXIT(("!\n")); return; } //InstallTabSrv
/*++
@doc INTERNAL
@func VOID | SetTabSrvConfig | Set service configuration.
@parm IN SC_HANDLE | hService | Service handle.
@rvalue None. --*/
VOID SetTabSrvConfig( IN SC_HANDLE hService ) { TRACEPROC("SetTabSrvConfig", 2) SERVICE_FAILURE_ACTIONS FailActions; SC_ACTION Actions = {SC_ACTION_RESTART, 10000}; //restart after 10 sec.
TRACEENTER(("(hService=%x)\n", hService));
FailActions.dwResetPeriod = 86400; //reset failure count after 1 day.
FailActions.lpRebootMsg = FailActions.lpCommand = NULL; FailActions.cActions = 1; FailActions.lpsaActions = &Actions; if (!ChangeServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, &FailActions)) { TABSRVERR(("Failed to set failure actions (err=%d)\n", GetLastError())); }
TRACEEXIT(("!\n")); return; } //SetTabSrvConfig
/*++
@doc INTERNAL
@func VOID | RemoveTabSrv | Remove TabSrv service.
@parm None.
@rvalue None. --*/
VOID RemoveTabSrv( VOID ) { TRACEPROC("RemoveTabSrv", 2) SC_HANDLE hSCM; SC_HANDLE hService;
TRACEENTER(("()\n"));
//
// Stop the service first
//
StopTabSrv();
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); TRACEASSERT(hSCM != NULL);
hService = OpenService(hSCM, gtszTabSrvName, DELETE); if (hService != NULL) { DeleteService(hService); CloseServiceHandle(hService); } else { TABSRVERR(("Failed to open service for delete.\n")); }
CloseServiceHandle(hSCM);
TRACEEXIT(("!\n")); return; } //RemoveTabSrv
/*++
@doc INTERNAL
@func VOID | StartTabSrv | Start TabSrv service.
@parm None.
@rvalue None. --*/
VOID StartTabSrv( VOID ) { TRACEPROC("StartTabSrv", 2) SC_HANDLE hSCM; SC_HANDLE hService;
TRACEENTER(("()\n"));
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); TRACEASSERT(hSCM != NULL);
hService = OpenService(hSCM, gtszTabSrvName, SERVICE_START); if (hService != NULL) { if (!StartService(hService, 0, NULL)) { TABSRVERR(("Failed to start service (err=%d).\n", GetLastError())); } CloseServiceHandle(hService); } else { TABSRVERR(("Failed to open service for start.\n")); }
CloseServiceHandle(hSCM);
TRACEEXIT(("!\n")); return; } //StartTabSrv
/*++
@doc INTERNAL
@func VOID | StopTabSrv | Stop TabSrv service.
@parm None.
@rvalue None. --*/
VOID StopTabSrv( VOID ) { TRACEPROC("StopTabSrv", 2) SC_HANDLE hSCM; SC_HANDLE hService; SERVICE_STATUS Status;
TRACEENTER(("()\n"));
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); TRACEASSERT(hSCM != NULL);
hService = OpenService(hSCM, gtszTabSrvName, SERVICE_STOP); if (hService != NULL) { if (!ControlService(hService, SERVICE_CONTROL_STOP, &Status)) { TABSRVERR(("Failed to stop service (err=%d).\n", GetLastError())); } CloseServiceHandle(hService); } else { TABSRVERR(("Failed to open service for stop.\n")); }
CloseServiceHandle(hSCM);
TRACEEXIT(("!\n")); return; } //StopTabSrv
/*++
@doc EXTERNAL
@func VOID | TabSrvServiceHandler | Service handler.
@parm IN DWORD | dwControl | Control code.
@rvalue None. --*/
VOID WINAPI TabSrvServiceHandler( IN DWORD dwControl ) { TRACEPROC("TabSrvServiceHandler", 3)
TRACEENTER(("(Control=%s)\n", LookupName(dwControl, ServiceControlNames)));
switch (dwControl) { case SERVICE_CONTROL_INTERROGATE: SetServiceStatus(ghServStatus, &gServStatus); break;
case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: SET_SERVICE_STATUS(SERVICE_STOP_PENDING); TabSrvTerminate(TRUE); break;
default: TRACEWARN(("Unhandled control code (%s).\n", LookupName(dwControl, ServiceControlNames))); }
TRACEEXIT(("!\n")); return; } //TabSrvServiceHandler
#ifdef ALLOW_DEBUG
/*++
@doc EXTERNAL
@func BOOL | TabSrvConsoleHandler | Console control handler.
@parm IN DWORD | dwControl | Control code.
@rvalue SUCCESS | Returns TRUE - handle the event. @rvalue FAILURE | Returns FALSE - do not handle the event. --*/
BOOL WINAPI TabSrvConsoleHandler( IN DWORD dwControl ) { TRACEPROC("TabSrvConsoleHandler", 3) BOOL rc = FALSE;
TRACEENTER(("(Control=%s)\n", LookupName(dwControl, ConsoleControlNames)));
switch (dwControl) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: SET_SERVICE_STATUS(SERVICE_STOP_PENDING); TabSrvTerminate(TRUE); rc = TRUE; break; }
TRACEEXIT(("=%x\n", rc)); return rc; } //TabSrvConsoleHandler
#endif
/*++
@doc EXTERNAL
@func VOID | TabSrvMain | Service entry point.
@parm IN int | icArgs | Specifies number of command line arguments. @parm IN PSZ * | apszArgs | Points to the array of argument strings.
@rvalue None. --*/
VOID WINAPI TabSrvMain( IN DWORD icArgs, IN LPTSTR *aptszArgs ) { TRACEPROC("TabSrvMain", 2)
TRACEENTER(("(icArgs=%d,aptszArgs=%p)\n", icArgs, aptszArgs));
if ((icArgs == 2) && (lstrcmpi(aptszArgs[1], TEXT("/config")) == 0)) { SC_HANDLE hSCM; SC_HANDLE hService;
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); TRACEASSERT(hSCM != NULL);
hService = OpenService(hSCM, gtszTabSrvName, SERVICE_ALL_ACCESS | SERVICE_CHANGE_CONFIG); if (hService != NULL) { SetTabSrvConfig(hService); CloseServiceHandle(hService); } else { TABSRVERR(("Failed to open service for config.\n")); } CloseServiceHandle(hSCM); }
InitializeListHead(&glistNotifyClients);
ghcurPressHold = LoadCursor(ghMod, MAKEINTRESOURCE(IDC_PRESSHOLD)); TRACEASSERT(ghcurPressHold != NULL); ghcurNormal = LoadCursor(ghMod, MAKEINTRESOURCE(IDC_NORMAL)); TRACEASSERT(ghcurNormal != NULL);
ghDesktopSwitchEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("WinSta0_DesktopSwitch")); TRACEASSERT(ghDesktopSwitchEvent != NULL);
ghmutNotifyList = CreateMutex(NULL, FALSE, NULL); TRACEASSERT(ghmutNotifyList != NULL);
gdevDigitizer.hStopDeviceEvent = CreateEvent(NULL, FALSE, FALSE, NULL); TRACEASSERT(gdevDigitizer.hStopDeviceEvent != NULL); FindThread(TSF_DIGITHREAD)->pvSDTParam = gdevDigitizer.hStopDeviceEvent; gdevButtons.hStopDeviceEvent = CreateEvent(NULL, FALSE, FALSE, NULL); TRACEASSERT(gdevButtons.hStopDeviceEvent != NULL); FindThread(TSF_BUTTONTHREAD)->pvSDTParam = gdevButtons.hStopDeviceEvent; ghHotkeyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); TRACEASSERT(ghHotkeyEvent != NULL); ghRefreshEvent = CreateEvent(NULL, FALSE, FALSE, NULL); TRACEASSERT(ghRefreshEvent != NULL);
gServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; gServStatus.dwCurrentState = SERVICE_START_PENDING; gServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; gServStatus.dwWin32ExitCode = NO_ERROR; gServStatus.dwServiceSpecificExitCode = NO_ERROR; gServStatus.dwCheckPoint = 0; gServStatus.dwWaitHint = 0; UpdateRotation();
if (!(gdwfTabSrv & TSF_DEBUG_MODE)) { ghServStatus = RegisterServiceCtrlHandler(gtszTabSrvName, TabSrvServiceHandler); TRACEASSERT(ghServStatus != NULL); SetServiceStatus(ghServStatus, &gServStatus); }
//
// For a noninteractive service application to interact with the user,
// it must open the user's window station ("WinSta0") and desktop
// ("Default").
//
HWINSTA hwinstaSave = GetProcessWindowStation(); HWINSTA hwinsta = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED); TRACEASSERT(hwinstaSave != NULL); if (hwinsta != NULL) { SetProcessWindowStation(hwinsta); InitConfigFromReg(); GetInputDesktopName(gtszInputDesktop, sizeof(gtszInputDesktop)); if (InitThreads(gTabSrvThreads, NUM_THREADS)) { SET_SERVICE_STATUS(SERVICE_RUNNING); WaitForTermination(); SET_SERVICE_STATUS(SERVICE_STOPPED); } else { TabSrvTerminate(TRUE); }
if (hwinstaSave != NULL) { SetProcessWindowStation(hwinstaSave); } CloseWindowStation(hwinsta); } else { TABSRVERR(("Failed to open window station.\n")); }
DWORD rcWait = WaitForSingleObject(ghmutNotifyList, INFINITE); if (rcWait == WAIT_OBJECT_0) { PLIST_ENTRY plist; PNOTIFYCLIENT NotifyClient;
while (!IsListEmpty(&glistNotifyClients)) { plist = RemoveHeadList(&glistNotifyClients); NotifyClient = CONTAINING_RECORD(plist, NOTIFYCLIENT, list); free(NotifyClient); } ReleaseMutex(ghmutNotifyList); } else { TABSRVERR(("Failed to wait for RawPtList Mutex (rcWait=%x,err=%d).\n", rcWait, GetLastError())); }
CloseHandle(ghRefreshEvent); CloseHandle(ghHotkeyEvent); CloseHandle(gdevDigitizer.hStopDeviceEvent); CloseHandle(gdevButtons.hStopDeviceEvent); ghHotkeyEvent = NULL; gdevDigitizer.hStopDeviceEvent = NULL; gdevButtons.hStopDeviceEvent = NULL; CloseHandle(ghmutNotifyList); ghmutNotifyList = NULL; CloseHandle(ghDesktopSwitchEvent); ghDesktopSwitchEvent = NULL; DestroyCursor(ghcurNormal); ghcurNormal = NULL; DestroyCursor(ghcurPressHold); ghcurPressHold = NULL; gdwfTabSrv = 0; TRACEINFO(1, ("Out of here.\n"));
TRACEEXIT(("!\n")); return; } //TabSrvMain
/*++
@doc INTERNAL
@func VOID | InitConfigFromReg | Initialize configuration from registry.
@parm None.
@rvalue None. --*/
VOID InitConfigFromReg( VOID ) { TRACEPROC("InitConfigFromReg", 2) LONG rcCfg; LPTSTR lptstrPenTilt; PTSTHREAD MouseThread;
TRACEENTER(("()\n"));
rcCfg = ReadConfig(gtszGestureSettings, (LPBYTE)&gConfig.GestureSettings, sizeof(gConfig.GestureSettings)); if ((rcCfg != ERROR_SUCCESS) || (gConfig.GestureSettings.dwcbLen != sizeof(gConfig.GestureSettings))) { if (rcCfg == ERROR_SUCCESS) { TABSRVERR(("Incorrect size on GestureSettings, use default.\n")); } gConfig.GestureSettings = gDefGestureSettings; }
MouseThread = FindThread(TSF_MOUSETHREAD); if (MouseThread != NULL) { if (gConfig.GestureSettings.dwfFeatures & GESTURE_FEATURE_MOUSE_ENABLED) { MouseThread->dwfThread |= THREADF_ENABLED; } else { MouseThread->dwfThread &= ~THREADF_ENABLED; } }
lptstrPenTilt = (gdwfTabSrv & TSF_PORTRAIT_MODE)? TEXT("PenTilt_Portrait"): TEXT("PenTilt_Landscape"), rcCfg = ReadConfig(lptstrPenTilt, (LPBYTE)&gConfig.PenTilt, sizeof(gConfig.PenTilt));
rcCfg = ReadConfig(gtszLinearityMap, (LPBYTE)&gConfig.LinearityMap, sizeof(gConfig.LinearityMap)); if ((rcCfg == ERROR_SUCCESS) && (gConfig.LinearityMap.dwcbLen == sizeof(gConfig.LinearityMap))) { gdwfTabSrv |= TSF_HAS_LINEAR_MAP; }
rcCfg = ReadConfig(gtszButtonSettings, (LPBYTE)&gConfig.ButtonSettings, sizeof(gConfig.ButtonSettings)); if ((rcCfg != ERROR_SUCCESS) || (gConfig.ButtonSettings.dwcbLen != sizeof(gConfig.ButtonSettings))) { if (rcCfg == ERROR_SUCCESS) { TABSRVERR(("Incorrect size on ButtonSettings, use default.\n")); } gConfig.ButtonSettings = gDefButtonSettings; }
BOOL fPortraitMode2 = FALSE; rcCfg = ReadConfig(gtszPortraitMode2, (LPBYTE)&fPortraitMode2, sizeof(fPortraitMode2)); if ((rcCfg == ERROR_SUCCESS) && fPortraitMode2) { gdwfTabSrv |= TSF_PORTRAIT_MODE2; }
TRACEEXIT(("!\n")); return; } //InitConfigFromReg
/*++
@doc INTERNAL
@func BOOL | InitThreads | Initialize various threads.
@parm PTSTHREAD | pThreads | Points to the thread array for the threads to start. @parm int | nThreads | Specifies the number of threads in the array.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL InitThreads( IN PTSTHREAD pThreads, IN int nThreads ) { TRACEPROC("InitThreads", 2) BOOL rc = TRUE; int i; unsigned uThreadID;
TRACEENTER(("(pThreads=%p,NumThreads=%d)\n", pThreads, nThreads));
for (i = 0; i < nThreads; ++i) { if (pThreads[i].dwfThread & THREADF_ENABLED) { pThreads[i].hThread = (HANDLE)_beginthreadex( NULL, 0, pThreads[i].pfnThread, pThreads[i].pvParam? pThreads[i].pvParam: &pThreads[i], 0, &uThreadID); if (pThreads[i].hThread != NULL) { gdwfTabSrv |= pThreads[i].dwThreadTag; } else { TABSRVERR(("Failed to create %s thread, LastError=%d.\n", pThreads[i].pszThreadName, GetLastError())); rc = FALSE; break; } } } SetEvent(ghRefreshEvent);
TRACEEXIT(("=%x\n", rc)); return rc; } //InitThreads
/*++
@doc INTERNAL
@func PTSTHREAD | FindThread | Find a thread in the thread table.
@parm DWORD | dwThreadTag | Specifies the thread to look for.
@rvalue SUCCESS | Returns pointer to the thread entry in table. @rvalue FAILURE | Returns NULL. --*/
PTSTHREAD FindThread( IN DWORD dwThreadTag ) { TRACEPROC("FindThread", 2) PTSTHREAD Thread = NULL; int i;
TRACEENTER(("(ThreadTag=%x)\n", dwThreadTag));
for (i = 0; i < NUM_THREADS; ++i) { if (gTabSrvThreads[i].dwThreadTag == dwThreadTag) { Thread = &gTabSrvThreads[i]; break; } }
TRACEEXIT(("=%p\n", Thread)); return Thread; } //FindThread
/*++
@doc INTERNAL
@func VOID | WaitForTermination | Wait for termination.
@parm None.
@rvalue None. --*/
VOID WaitForTermination( VOID ) { TRACEPROC("WaitForTermination", 2) HANDLE ahWait[NUM_THREADS + 3]; DWORD rcWait; int i;
TRACEENTER(("()\n"));
ahWait[0] = ghDesktopSwitchEvent; ahWait[1] = ghHotkeyEvent; ahWait[2] = ghRefreshEvent;
//
// Wait for termination.
//
for (;;) { DWORD n = 3;
for (i = 0; i < NUM_THREADS; ++i) { if (gTabSrvThreads[i].hThread != NULL) { ahWait[n] = gTabSrvThreads[i].hThread; gTabSrvThreads[i].iThreadStatus = WAIT_OBJECT_0 + n; n++; } else { gTabSrvThreads[i].iThreadStatus = -1; } }
rcWait = WaitForMultipleObjects(n, ahWait, FALSE, INFINITE); if ((rcWait == WAIT_OBJECT_0) || (rcWait == WAIT_OBJECT_0 + 1)) { TCHAR tszDesktop[32]; BOOL fDoSwitch = TRUE;
if (rcWait == WAIT_OBJECT_0 + 1) { //
// Send hot key event and tell all threads to switch.
//
TRACEINFO(1, ("Send Hotkey.\n")); SendAltCtrlDel(); if (GetInputDesktopName(tszDesktop, sizeof(tszDesktop))) { TRACEINFO(1, ("[CAD] New input desktop=%s\n", tszDesktop)); lstrcpyn(gtszInputDesktop, tszDesktop, ARRAYSIZE(gtszInputDesktop)); } } else if (GetInputDesktopName(tszDesktop, sizeof(tszDesktop))) { if (lstrcmpi(tszDesktop, gtszInputDesktop) == 0) { //
// It seems that when the user logs off, two desktop
// switches are signaled in quick succession. The
// desktop is still 'Default' after the first switch
// is signaled. So we don't really want to switch
// all threads to the same desktop.
//
TRACEINFO(1, ("Same desktop, don't switch (Desktop=%s).\n", tszDesktop)); fDoSwitch = FALSE; } else { TRACEINFO(1, ("New input desktop=%s\n", tszDesktop)); lstrcpyn(gtszInputDesktop, tszDesktop, ARRAYSIZE(gtszInputDesktop)); } }
if (fDoSwitch) { //
// We are swtiching, tell all threads that need to switch
// desktop to switch.
//
TabSrvTerminate(FALSE); } } else if (rcWait != WAIT_OBJECT_0 + 2) { for (i = 0; i < NUM_THREADS; ++i) { if (rcWait == (DWORD)gTabSrvThreads[i].iThreadStatus) { CloseHandle(gTabSrvThreads[i].hThread); gTabSrvThreads[i].hThread = NULL; gdwfTabSrv &= ~gTabSrvThreads[i].dwThreadTag; TRACEINFO(1, ("%s thread is killed.\n", gTabSrvThreads[i].pszThreadName)); //
// If a thread died unexpectedly and it is marked
// restartable, restart it.
//
if (!(gdwfTabSrv & TSF_TERMINATE) && (gTabSrvThreads[i].dwfThread & THREADF_RESTARTABLE)) { if (gTabSrvThreads[i].dwcRestartTries < MAX_RESTARTS) { TRACEINFO(1, ("%s thread died unexpectedly, restarting (count=%d)\n", gTabSrvThreads[i].pszThreadName, gTabSrvThreads[i].dwcRestartTries)); InitThreads(&gTabSrvThreads[i], 1); gTabSrvThreads[i].dwcRestartTries++; } else { TABSRVERR(("%s thread exceeds restart maximum.\n", gTabSrvThreads[i].pszThreadName)); } } break; } }
if (i == NUM_THREADS) { TABSRVERR(("WaitForMultipleObjects failed (rcWait=%x,err=%d).\n", rcWait, GetLastError())); break; } }
if (!(gdwfTabSrv & TSF_ALLTHREAD)) { //
// All threads are dead, we can quit now.
//
break; } }
TRACEEXIT(("!\n")); return; } //WaitForTermination
/*++
@doc INTERNAL
@func VOID | TabSrvTerminate | Do clean up.
@parm IN BOOL | fTerminate | TRUE if real termination, otherwise switching desktop.
@rvalue None. --*/
VOID TabSrvTerminate( IN BOOL fTerminate ) { TRACEPROC("TabSrvTerminate", 2) int i;
TRACEENTER(("(fTerminate=%x)\n", fTerminate));
if (fTerminate) { gdwfTabSrv |= TSF_TERMINATE; }
for (i = 0; i < NUM_THREADS; ++i) { if (gTabSrvThreads[i].dwfThread & (THREADF_SDT_POSTMSG | THREADF_SDT_SETEVENT)) { if (gdwfTabSrv & gTabSrvThreads[i].dwThreadTag) { TRACEINFO(1, (fTerminate? "Kill %s thread.\n": "Switch %s thread desktop.\n", gTabSrvThreads[i].pszThreadName)); TRACEASSERT(gTabSrvThreads[i].pvSDTParam != NULL);
if (gTabSrvThreads[i].dwfThread & THREADF_SDT_POSTMSG) { if (IsWindow((HWND)gTabSrvThreads[i].pvSDTParam)) { PostMessage((HWND)gTabSrvThreads[i].pvSDTParam, WM_CLOSE, 0, 0); } else { TRACEINFO(1, ("%s thread window handle (%x) is not valid.\n", gTabSrvThreads[i].pszThreadName, gTabSrvThreads[i].pvSDTParam)); } } else { SetEvent((HANDLE)gTabSrvThreads[i].pvSDTParam); } } else if (!fTerminate && (gTabSrvThreads[i].dwcRestartTries >= MAX_RESTARTS)) { TRACEINFO(1, ("Retrying to start %s thread.\n", gTabSrvThreads[i].pszThreadName)); InitThreads(&gTabSrvThreads[i], 1); gTabSrvThreads[i].dwcRestartTries = 1; } } }
if (fTerminate && (gdwfTabSrv & TSF_RPCTHREAD)) { RpcMgmtStopServerListening(NULL); }
TRACEEXIT(("!\n")); return; } //TabSrvTerminate
/*++
@doc INTERNAL
@func VOID | TabSrvLogError | Log the error in the event log.
@parm IN PSZ | pszFormat | Points to the format string. @parm ... | String arguments.
@rvalue None. --*/
VOID TabSrvLogError( IN PSZ pszFormat, ... ) { TRACEPROC("TabSrvLogError", 5)
TRACEENTER(("(Format=%s,...)\n", pszFormat));
if (!(gdwfTabSrv & TSF_DEBUG_MODE)) { HANDLE hEventLog;
hEventLog = RegisterEventSource(NULL, TEXT(STR_TABSRV_NAME)); if (hEventLog != NULL) { char szMsg[256]; LPCSTR psz = szMsg; va_list arglist;
va_start(arglist, pszFormat); wvsprintfA(szMsg, pszFormat, arglist); va_end(arglist);
ReportEventA(hEventLog, //handle of event source
EVENTLOG_ERROR_TYPE, //event type
0, //event category
0, //event ID
NULL, //current user's SID
1, //number of strings
0, //size of raw data
&psz, //array of strings
NULL); //no raw data
DeregisterEventSource(hEventLog); } }
TRACEEXIT(("!\n")); return; } //TabSrvLogError
/*++
@doc INTERNAL
@func LONG | ReadConfig | Read TabSrv configuration from registry.
@parm IN LPCTSTR | lptstrValueName | Points to the registry value name string. @parm OUT LPBYTE | lpbData | Points to the buffer to hold the value read. @parm IN DWORD | dwcb | Specifies the size of the buffer.
@rvalue SUCCESS | Returns ERROR_SUCCESS. @rvalue FAILURE | Returns registry error code. --*/
LONG ReadConfig( IN LPCTSTR lptstrValueName, OUT LPBYTE lpbData, IN DWORD dwcb ) { TRACEPROC("ReadConfig", 3) LONG rc; HKEY hkey;
TRACEENTER(("(Name=%s,pData=%p,Len=%d)\n", lptstrValueName, lpbData, dwcb));
rc = RegCreateKey(HKEY_LOCAL_MACHINE, gtszRegPath, &hkey); if (rc == ERROR_SUCCESS) { rc = RegQueryValueEx(hkey, lptstrValueName, NULL, NULL, lpbData, &dwcb); if (rc != ERROR_SUCCESS) { TRACEWARN(("Failed to read \"%s\" from registry (rc=%d).\n", lptstrValueName, rc)); }
RegCloseKey(hkey); } else { TABSRVERR(("Failed to open registry key to read configuration (rc=%d).\n", rc)); }
TRACEEXIT(("=%d\n", rc)); return rc; } //ReadConfig
/*++
@doc INTERNAL
@func LONG | WriteConfig | Write TabSrv configuration to registry.
@parm IN LPCTSTR | lptstrValueName | Points to the registry value name string. @parm IN DWORD | dwType | Specifies the registry value type. name string. @parm IN LPBYTE | lpbData | Points to the buffer to hold the value read. @parm IN DWORD | dwcb | Specifies the size of the buffer.
@rvalue SUCCESS | Returns ERROR_SUCCESS. @rvalue FAILURE | Returns registry error code. --*/
LONG WriteConfig( IN LPCTSTR lptstrValueName, IN DWORD dwType, IN LPBYTE lpbData, IN DWORD dwcb ) { TRACEPROC("WriteConfig", 3) LONG rc; HKEY hkey;
TRACEENTER(("(Name=%s,Type=%d,pData=%p,Len=%d)\n", lptstrValueName, dwType, lpbData, dwcb));
rc = RegCreateKey(HKEY_LOCAL_MACHINE, gtszRegPath, &hkey); if (rc == ERROR_SUCCESS) { rc = RegSetValueEx(hkey, lptstrValueName, 0, dwType, lpbData, dwcb); if (rc != ERROR_SUCCESS) { TRACEWARN(("Failed to write \"%s\" to registry (rc=%d).\n", lptstrValueName, rc)); } RegCloseKey(hkey); } else { TABSRVERR(("Failed to create registry key to write configuration (rc=%d).\n", rc)); }
TRACEEXIT(("=%d\n", rc)); return rc; } //WriteConfig
/*++
@doc INTERNAL
@func HRESULT | GetRegValueString | Get registry string value.
@parm IN HKEY | hkeyTopLevel | Top level registry key. @parm IN LPCTSTR | pszSubKey | Subkey string. @parm IN LPCTSTR | pszValueName | Value name string. @parm OUT LPTSTR | pszValueString | To hold value string. @parm IN OUT LPDWORD | lpdwcb | Specify size of ValueString and to hold result string size.
@rvalue SUCCESS | Returns ERROR_SUCCESS. @rvalue FAILURE | Returns registry error code. --*/
LONG GetRegValueString( IN HKEY hkeyTopLevel, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, OUT LPTSTR pszValueString, IN OUT LPDWORD lpdwcb ) { TRACEPROC("GetRegValueString", 3) LONG rc; HKEY hkey;
TRACEASSERT(lpdwcb != NULL); TRACEASSERT((pszValueString != NULL) || (*lpdwcb == 0)); TRACEENTER(("(hkTop=%x,SubKey=%s,ValueName=%s,ValueString=%p,Len=%d)\n", hkeyTopLevel, pszSubKey, pszValueName, pszValueString, *lpdwcb));
if (pszValueString != NULL) { pszValueString[0] = TEXT('\0'); }
rc = RegOpenKeyEx(hkeyTopLevel, pszSubKey, 0, KEY_READ, &hkey); if (rc == ERROR_SUCCESS) { DWORD dwType = 0;
rc = RegQueryValueEx(hkey, pszValueName, 0, &dwType, (LPBYTE)pszValueString, lpdwcb); if (rc == ERROR_SUCCESS) { if (dwType != REG_SZ) { TABSRVERR(("Invalid registry data type (type=%x).\n", dwType)); rc = ERROR_INVALID_DATATYPE; } } else { TABSRVERR(("Failed to read registry value %s\\%s (rc=%x).\n", pszSubKey, pszValueName, rc)); } RegCloseKey(hkey); } else { TABSRVERR(("Failed to open registry key %s (rc=%x).\n", pszSubKey, rc)); }
TRACEEXIT(("=%d\n", rc)); return rc; } //GetRegValueString
/*++
@doc INTERNAL
@func BOOL | SwitchThreadToInputDesktop | Switch thread to current input desktop.
@parm IN PTSTHREAD | pThread | Points to the thread structure.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL SwitchThreadToInputDesktop( IN PTSTHREAD pThread ) { TRACEPROC("SwitchThreadToInputDesktop", 2) BOOL rc = TRUE; HDESK hdesk;
TRACEENTER(("(pThread=%p)\n", pThread));
hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED); if (hdesk == NULL) { TRACEWARN(("Failed to open input desktop (err=%d), try Winlogon ...\n", GetLastError()));
hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED); if (hdesk == NULL) { TABSRVERR(("Failed to open winlogon desktop (err=%d).\n", GetLastError())); rc = FALSE; } }
if (rc == TRUE) { CloseDesktop(GetThreadDesktop(GetCurrentThreadId()));
rc = SetThreadDesktop(hdesk); if (rc) { TCHAR tszDesktop[32]; DWORD dwcb;
if (GetUserObjectInformation(hdesk, UOI_NAME, tszDesktop, sizeof(tszDesktop), &dwcb)) { TRACEINFO(1, ("Switch to Input desktop %s.\n", tszDesktop)); if (lstrcmpi(tszDesktop, TEXT("Winlogon")) == 0) { pThread->dwfThread |= THREADF_DESKTOP_WINLOGON; } else { pThread->dwfThread &= ~THREADF_DESKTOP_WINLOGON; }
if (lstrcmpi(tszDesktop, gtszInputDesktop) != 0) { TRACEINFO(1, ("Input desktop name out of sync (old=%s, new=%s).\n", gtszInputDesktop, tszDesktop)); lstrcpyn(gtszInputDesktop, tszDesktop, ARRAYSIZE(gtszInputDesktop)); } } } else { TABSRVERR(("Failed to set thread desktop (err=%d)\n", GetLastError())); } } else { TABSRVERR(("Failed to open input desktop (err=%d)\n", GetLastError())); }
TRACEEXIT(("=%x\n", rc)); return rc; } //SwitchThreadToInputDesktop
/*++
@doc INTERNAL
@func BOOL | GetInputDesktopName | Get current input desktop name.
@parm OUT LPTSTR | pszDesktopName | Point to a buffer to hold the desktop name. @parm IN DWORD | dwcbLen | Specifies length of buffer.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL GetInputDesktopName( OUT LPTSTR pszDesktopName, IN DWORD dwcbLen ) { TRACEPROC("GetInputDesktopName", 2) BOOL rc = FALSE; HDESK hdesk;
TRACEENTER(("(pszDesktopName=%p,Len=%d)\n", pszDesktopName, dwcbLen));
hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED); if (hdesk == NULL) { TRACEWARN(("Failed to open input desktop (err=%d), try Winlogon ...\n", GetLastError()));
hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED); if (hdesk == NULL) { TABSRVERR(("Failed to open winlogon desktop (err=%d).\n", GetLastError())); } }
if (hdesk != NULL) { if (GetUserObjectInformation(hdesk, UOI_NAME, pszDesktopName, dwcbLen, &dwcbLen)) { rc = TRUE; } else { TRACEWARN(("Failed to get desktop name (err=%d).\n", GetLastError())); } CloseDesktop(hdesk); } else { TRACEWARN(("failed to open input desktop (err=%d)\n", GetLastError())); }
TRACEEXIT(("=%x (DeskTopName=%s)\n", rc, pszDesktopName)); return rc; } //GetInputDesktopName
/*++
@doc INTERNAL
@func VOID | SendAltCtrlDel | Send Alt+Ctrl+Del
@parm None.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL SendAltCtrlDel( VOID ) { TRACEPROC("SendAltCtrlDel", 2) BOOL rc = FALSE; HWINSTA hwinstaSave; HDESK hdeskSave;
TRACEENTER(("()\n"));
hwinstaSave = GetProcessWindowStation(); hdeskSave = GetThreadDesktop(GetCurrentThreadId());
if ((hwinstaSave != NULL) && (hdeskSave != NULL)) { HWINSTA hwinsta; HDESK hdesk;
hwinsta = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED); if (hwinsta != NULL) { SetProcessWindowStation(hwinsta); hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED); if (hdesk != NULL) { HWND hwndSAS;
SetThreadDesktop(hdesk); hwndSAS = FindWindow(NULL, TEXT("SAS window")); if (hwndSAS != NULL) { SendMessage(hwndSAS, WM_HOTKEY, 0, 0); rc = TRUE; } else { TABSRVERR(("Failed to find SAS window (err=%d).\n", GetLastError())); } SetThreadDesktop(hdeskSave); CloseDesktop(hdesk); } else { TABSRVERR(("Failed to open Winlogon (err=%d).\n", GetLastError())); } SetProcessWindowStation(hwinsta); CloseWindowStation(hwinsta); } else { TABSRVERR(("Failed to open WinSta0 (err=%d).\n", GetLastError())); } } else { TABSRVERR(("GetProcessWindowStation or GetThreadDesktop failed (err=%d,hwinsta=%x,hdesk=%x).\n", GetLastError(), hwinstaSave, hdeskSave)); }
TRACEEXIT(("=%x\n", rc)); return rc; } //SendAltCtrlDel
/*++
@doc INTERNAL
@func VOID | NotifyClient | Check if we need to notify anybody.
@parm IN EVTNOTIFY | Event | Event to broadcast. @parm IN WPARAM | wParam | wParam to send in the message. @parm IN LPARAM | lParam | lParam to send in the message.
@rvalue None. --*/
VOID NotifyClient( IN EVTNOTIFY Event, IN WPARAM wParam, IN LPARAM lParam ) { TRACEPROC("NotifyClient", 5)
TRACEENTER(("(Event=%x,wParam=%x,lParam=%x)\n", Event, wParam, lParam));
if (!IsListEmpty(&glistNotifyClients)) { DWORD rcWait; PLIST_ENTRY plist; PNOTIFYCLIENT Client;
rcWait = WaitForSingleObject(ghmutNotifyList, INFINITE); if (rcWait == WAIT_OBJECT_0) { for (plist = glistNotifyClients.Flink; plist != &glistNotifyClients; plist = plist->Flink) { Client = CONTAINING_RECORD(plist, NOTIFYCLIENT, list); if (Client->Event == Event) { PostMessage(Client->hwnd, Client->uiMsg, wParam, lParam); } } ReleaseMutex(ghmutNotifyList); } else { TABSRVERR(("failed to wait for Notify list mutex (rcWait=%x,err=%d).\n", rcWait, GetLastError())); } }
TRACEEXIT(("!\n")); return; } //NotifyClient
/*++
@doc INTERNAL
@func BOOL | ImpersonateCurrentUser | Impersonate current logged on user.
@parm None.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL ImpersonateCurrentUser( VOID ) { TRACEPROC("ImpersonateCurrentUser", 3) BOOL rc = FALSE; HANDLE hToken;
TRACEENTER(("()\n"));
hToken = GetCurrentUserTokenW(L"WinSta0", TOKEN_ALL_ACCESS); if (hToken != NULL) { rc = ImpersonateLoggedOnUser(hToken);
if (rc == FALSE) { TABSRVERR(("Failed to impersonate logged on user (err=%d).\n", GetLastError())); } CloseHandle(hToken); } else { DWORD dwError = GetLastError();
if (dwError != ERROR_NOT_LOGGED_ON) { TABSRVERR(("Failed to get current user token (err=%d)\n", dwError)); } }
TRACEEXIT(("=%x\n", rc)); return rc; } //ImpersonateCurrentUser
/*++
@doc INTERNAL
@func BOOL | RunProcessAsUser | Run a process as the logged on user.
@parm IN LPTSTR | pszCmd | Process command.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL RunProcessAsUser( IN LPTSTR pszCmd ) { TRACEPROC("RunProcessAsUser", 3) BOOL rc = FALSE; HANDLE hImpersonateToken; HANDLE hPrimaryToken;
TRACEENTER(("(Cmd=%s)\n", pszCmd));
if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, TRUE, &hImpersonateToken)) { if (DuplicateTokenEx(hImpersonateToken, TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) { STARTUPINFO si; PROCESS_INFORMATION pi; LPVOID lpEnv = NULL;
if (!CreateEnvironmentBlock(&lpEnv, hImpersonateToken, TRUE)) { TABSRVERR(("Failed to create environment block (err=%d).\n", GetLastError())); lpEnv = NULL; }
memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.lpDesktop = TEXT("WinSta0\\Default");
if (CreateProcessAsUser(hPrimaryToken, NULL, pszCmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, lpEnv, NULL, &si, &pi)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); rc = TRUE; } else { TABSRVERR(("Failed to create process as user (err=%d).\n", GetLastError())); } if (lpEnv != NULL) { DestroyEnvironmentBlock(lpEnv); } CloseHandle(hPrimaryToken); } else { TABSRVERR(("Failed to duplicate token (err=%d).\n", GetLastError())); } CloseHandle(hImpersonateToken); } else { TABSRVERR(("Failed to open thread token (err=%d).\n", GetLastError())); }
TRACEEXIT(("=%x\n", rc)); return rc; } //RunProcessAsUser
/*++
@doc EXTERNAL
@func void __RPC_FAR * | MIDL_user_allocate | MIDL allocate.
@parm IN size_t | len | size of allocation.
@rvalue SUCCESS | Returns the pointer to the memory allocated. @rvalue FAILURE | Returns NULL. --*/
void __RPC_FAR * __RPC_USER MIDL_user_allocate( IN size_t len ) { TRACEPROC("MIDL_user_allocate", 5) void __RPC_FAR *ptr;
TRACEENTER(("(len=%d)\n", len));
ptr = malloc(len);
TRACEEXIT(("=%p\n", ptr)); return ptr; } //MIDL_user_allocate
/*++
@doc EXTERNAL
@func void | MIDL_user_free | MIDL free.
@parm IN void __PRC_FAR * | ptr | Points to the memory to be freed.
@rvalue None. --*/
void __RPC_USER MIDL_user_free( IN void __RPC_FAR *ptr ) { TRACEPROC("MIDL_user_free", 5)
TRACEENTER(("(ptr=%p)\n", ptr));
free(ptr);
TRACEEXIT(("!\n")); return; } //MIDL_user_free
|