登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

vnc service  

2007-07-25 16:15:36|  分类: Delphi |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
// Service-mode defines:
// Executable name
#define VNCAPPNAME "winvnc"
// Internal service name
#define VNCSERVICENAME "winvnc"
// Displayed service name
#define VNCSERVICEDISPLAYNAME "VNC Server"
// List of other required services ("dependency 1\0dependency 2\0\0")
// *** These need filling in properly
#define VNCDEPENDENCIES ""

// Internal service state
SERVICE_STATUS g_srvstatus; // current status of the service
SERVICE_STATUS_HANDLE g_hstatus;
DWORD g_error = 0;
DWORD g_servicethread = NULL;
char* g_errortext[256];

// Forward defines of internal service functions
void WINAPI ServiceMain(DWORD argc, char **argv);
void ServiceWorkThread(void *arg);
void ServiceStop();
void WINAPI ServiceCtrl(DWORD ctrlcode);
bool WINAPI CtrlHandler (DWORD ctrltype);
BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
// ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
bool g_servicemode = FALSE;

bool vncService::RunningAsService()
{
return g_servicemode;
}

bool vncService::KillRunningCopy()
{
// Locate the hidden WinVNC menu window
HWND hservwnd;
while ((hservwnd = FindWindow(MENU_CLASS_NAME, NULL)) != NULL)
{
// Post the message to WinVNC
PostMessage(hservwnd, WM_CLOSE, 0, 0);
omni_thread::sleep(1);
}
return TRUE;
}

// ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING WINVNC, IN ORDER
// THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER
// OPTION, WHEN RUNNING UNDER NT
bool vncService::PostUserHelperMessage()
{
// - Check the platform type
if (!IsWinNT()) return TRUE;
// - Get the current process ID
DWORD processId = GetCurrentProcessId();
// - Post it to the existing WinVNC
int retries = 6;
while (!PostToWinVNC(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId) && retries--)
omni_thread::sleep(10);
// - Wait until it's been used
omni_thread::sleep(5);
return retries;
}

bool vncService::PostReloadMessage()
{
// - Check the platform type
if (!IsWinNT()) return TRUE;
// - Get the current process ID
DWORD processId = GetCurrentProcessId();
// - Post it to the existing WinVNC
// FIXME: Code duplication, see PostUserHelperMessage().
int retries = 6;
while (!PostToWinVNC(MENU_RELOAD_MSG, 0, (LPARAM)processId) && retries--)
omni_thread::sleep(10);
// - Wait until it's been used
omni_thread::sleep(5);
return retries;
}

// ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
bool vncService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam)
{
// - Check the platform type
if (!IsWinNT() || !vncService::RunningAsService()) return TRUE;
// - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
// NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS)
{
vnclog.Print(LL_INTERR, VNCLOG("failed to close current registry hive\n"));
return FALSE;
}
// - Revert to our own identity
RevertToSelf();
g_impersonating_user = FALSE;
// - Open the specified process
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
if (processHandle == NULL)
{
vnclog.Print(LL_INTERR, VNCLOG("failed to open specified process, error=%d\n"), GetLastError());
return FALSE;
}
// - Get the token for the given process
HANDLE userToken = NULL;
if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &userToken))
{
vnclog.Print(LL_INTERR, VNCLOG("failed to get user token, error=%d\n"), GetLastError());
CloseHandle(processHandle);
return FALSE;
}
CloseHandle(processHandle);
// - Set this thread to impersonate them
if (!ImpersonateLoggedOnUser(userToken))
{
vnclog.Print(LL_INTERR, VNCLOG("failed to impersonate user, error=%d\n"), GetLastError());
CloseHandle(userToken);
return FALSE;
}
CloseHandle(userToken);
g_impersonating_user = TRUE;
vnclog.Print(LL_INTINFO, VNCLOG("impersonating logged on user\n"));
return TRUE;
}

// SERVICE MAIN ROUTINE
int vncService::WinVNCServiceMain()
{
typedef DWORD (WINAPI * RegisterServiceProc)(DWORD, DWORD);
const ULONG RSP_SIMPLE_SERVICE = 0x00000001;
const ULONG RSP_UNREGISTER_SERVICE = 0x00000000;
//
g_servicemode = TRUE;
// How to run as a service depends upon the OS being used
switch (g_platform_id)
{
case VER_PLATFORM_WIN32_WINDOWS: // Windows 95/98
{
// Obtain a handle to the kernel library
HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
if (kerneldll == NULL) break;
// And find the RegisterServiceProcess function
RegisterServiceProc RegisterService;
RegisterService = (RegisterServiceProc) GetProcAddress(kerneldll, "RegisterServiceProcess");
if (RegisterService == NULL) break;
// Register this process with the OS as a service!
RegisterService(NULL, RSP_SIMPLE_SERVICE);
// Run the service itself
WinVNCAppMain();
// Then remove the service from the system service table
RegisterService(NULL, RSP_UNREGISTER_SERVICE);
// Free the kernel library
FreeLibrary(kerneldll);
// *** If we don't kill the process directly here, then
// for some reason, WinVNC crashes...
// *** Is this now fixed (with the stdcall patch above)?
//ExitProcess(0);
break;
}
case VER_PLATFORM_WIN32_NT: // Windows NT
{
// Create a service entry table
SERVICE_TABLE_ENTRY dispatchTable[] = {{VNCSERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain}, {NULL, NULL}};
// Call the service control dispatcher with our entry table
if (!StartServiceCtrlDispatcher(dispatchTable)) LogErrorMsg("StartServiceCtrlDispatcher failed.");
break;
}
};
return 0;
}

// SERVICE MAIN ROUTINE
void WINAPI ServiceMain(DWORD argc, char**argv)
{
// Register the service control handler
g_hstatus = RegisterServiceCtrlHandler(VNCSERVICENAME, ServiceCtrl);
if (g_hstatus == 0) return;
// Set up some standard service state values
g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
g_srvstatus.dwServiceSpecificExitCode = 0;
// Give this status to the SCM
if (!ReportStatus(SERVICE_START_PENDING, // Service state
NO_ERROR, // Exit code type
15000)) // Hint as to how long WinVNC should have hung before you assume error
{
ReportStatus(SERVICE_STOPPED, g_error, 0);
return;
}
// Now start the service for real
omni_thread *workthread = omni_thread::create(ServiceWorkThread);
return;
}

// SERVICE START ROUTINE - thread that calls WinVNCAppMain
void ServiceWorkThread(void *arg)
{
// Save the current thread identifier
g_servicethread = GetCurrentThreadId();
// report the status to the service control manager.
if (!ReportStatus( SERVICE_RUNNING, // service state
NO_ERROR, // exit code
0)) // wait hint
return;
// RUN!
WinVNCAppMain();
// Mark that we're no longer running
g_servicethread = NULL;
// Tell the service manager that we've stopped.
ReportStatus(SERVICE_STOPPED, g_error, 0);
}

// SERVICE STOP ROUTINE - post a quit message to the relevant thread
void ServiceStop()
{
// Post a quit message to the main service thread
if (g_servicethread != NULL)
{
vnclog.Print(LL_INTINFO, VNCLOG("quitting from ServiceStop\n"));
PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
}
}

// SERVICE INSTALL ROUTINE
int vncService::ReinstallService()
{
RemoveService(1);
InstallService(0);
return 0;
}

int vncService::InstallService(BOOL silent)
{
const int pathlength = 2048;
char path[pathlength];
char servicecmd[pathlength];
// Get the filename of this executable
if (GetModuleFileName(NULL, path, pathlength-(strlen(winvncRunService)+2)) == 0)
{
if (!silent) MessageBox(NULL, "Unable to install WinVNC service", szAppName, MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Append the service-start flag to the end of the path:
if (strlen(path) + 4 + strlen(winvncRunService) < pathlength)
sprintf(servicecmd, "\"%s\" %s", path, winvncRunService);
else
return 0;
// How to add the WinVNC service depends upon the OS
switch (g_platform_id)
{
case VER_PLATFORM_WIN32_WINDOWS: // Windows 95/98
{
// Locate the RunService registry entry
HKEY runservices;
if (RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices", &runservices) != ERROR_SUCCESS)
{
if (!silent) MessageBox(NULL, "The SCM could not be contacted - the WinVNC service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
break;
}
// Attempt to add a WinVNC key
if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS)
{
RegCloseKey(runservices);
if (!silent) MessageBox(NULL, "The WinVNC service could not be registered", szAppName, MB_ICONEXCLAMATION | MB_OK);
break;
}
RegCloseKey(runservices);
// We have successfully installed the service!
if (!silent)
{
vncTimedMsgBox::Do(
"The WinVNC service was successfully installed\n"
"The service will start now and will automatically\n"
"be run the next time this machine is reset",
szAppName, MB_ICONINFORMATION | MB_OK);
}
// Run the service...
STARTUPINFO si;
si.cb = sizeof(si);
si.cbReserved2 = 0;
si.lpReserved = NULL;
si.lpReserved2 = NULL;
si.dwFlags = 0;
si.lpTitle = NULL;
PROCESS_INFORMATION pi;
if (!CreateProcess(
NULL, servicecmd, // Program name & path
NULL, NULL, // Security attributes
FALSE, // Inherit handles?
NORMAL_PRIORITY_CLASS, // Extra startup flags
NULL, // Environment table
NULL, // Current directory
&si, &pi))
{
if (!silent) MessageBox(NULL, "The WinVNC service failed to start", szAppName, MB_ICONSTOP | MB_OK);
break;
}
break;
}
case VER_PLATFORM_WIN32_NT: // Windows NT
{
SC_HANDLE hservice;
SC_HANDLE hsrvmanager;
// Open the default, local Service Control Manager database
hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hsrvmanager == NULL)
{
if (!silent) MessageBox(NULL, "The Service Control Manager could not be contacted - the WinVNC service was not registered", szAppName, MB_ICONEXCLAMATION | MB_OK);
break;
}
// Create an entry for the WinVNC service
hservice = CreateService(
hsrvmanager, // SCManager database
VNCSERVICENAME, // name of service
VNCSERVICEDISPLAYNAME, // name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
servicecmd, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
VNCDEPENDENCIES, // dependencies
NULL, // LocalSystem account
NULL); // no password
if (hservice == NULL)
{
DWORD error = GetLastError();
if (!silent)
{
if (error == ERROR_SERVICE_EXISTS)
MessageBox(NULL, "The WinVNC service is already registered", szAppName, MB_ICONEXCLAMATION | MB_OK);
else
MessageBox(NULL, "The WinVNC service could not be registered", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
CloseServiceHandle(hsrvmanager);
break;
}
CloseServiceHandle(hsrvmanager);
CloseServiceHandle(hservice);
// Now install the servicehelper registry setting...
// Locate the RunService registry entry
HKEY runapps;
if (RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &runapps) != ERROR_SUCCESS)
{
if (!silent) MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
else
{
char servicehelpercmd[pathlength];
// Append the service-helper-start flag to the end of the path:
if (strlen(path) + 4 + strlen(winvncRunServiceHelper) < pathlength)
sprintf(servicehelpercmd, "\"%s\" %s", path, winvncRunServiceHelper);
else
return 0;
// Add the VNCserviceHelper entry
if (RegSetValueEx(runapps, szAppName, 0, REG_SZ, (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS)
{
if (!silent) MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
RegCloseKey(runapps);
}
// Everything went fine
if (!silent)
{
vncTimedMsgBox::Do(
"The WinVNC service was successfully registered\n"
"The service may be started from the Control Panel, and will\n"
"automatically be run the next time this machine is reset",
szAppName, MB_ICONINFORMATION | MB_OK);
}
}
break;
};
return 0;
}

// SERVICE REMOVE ROUTINE
int vncService::RemoveService(BOOL silent)
{
// How to remove the WinVNC service depends upon the OS
switch (g_platform_id)
{
case VER_PLATFORM_WIN32_WINDOWS: // Windows 95/98
{
// Locate the RunService registry entry
HKEY runservices;
if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices", &runservices) != ERROR_SUCCESS)
{
if (!silent) MessageBox(NULL, "The Service Control Manager could not be contacted - the WinVNC service was not unregistered", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
else
{
// Attempt to delete the WinVNC key
if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS)
{
RegCloseKey(runservices);
if (!silent) MessageBox(NULL, "The WinVNC service could not be unregistered", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
RegCloseKey(runservices);
break;
}
// Try to kill any running copy of WinVNC
if (!KillRunningCopy())
{
if (!silent) MessageBox(NULL, "The WinVNC service could not be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
break;
}
// We have successfully removed the service!
if (!silent) vncTimedMsgBox::Do("The WinVNC service has been unregistered", szAppName, MB_ICONINFORMATION | MB_OK);
break;
}
case VER_PLATFORM_WIN32_NT: // Windows NT
{
SC_HANDLE hservice;
SC_HANDLE hsrvmanager;
// Attempt to remove the service-helper hook
HKEY runapps;
if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &runapps) == ERROR_SUCCESS)
{
// Attempt to delete the WinVNC key
if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS)
{
if (!silent) MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
RegCloseKey(runapps);
}
// Open the SCM
hsrvmanager = OpenSCManager( NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS); // access required
if (hsrvmanager)
{
hservice = OpenService(hsrvmanager, VNCSERVICENAME, SERVICE_ALL_ACCESS);
if (hservice != NULL)
{
SERVICE_STATUS status;
// Try to stop the WinVNC service
if (ControlService(hservice, SERVICE_CONTROL_STOP, &status))
{
while(QueryServiceStatus(hservice, &status))
{
if (status.dwCurrentState == SERVICE_STOP_PENDING)
Sleep(1000);
else
break;
}
if (status.dwCurrentState != SERVICE_STOPPED)
{
if (!silent) MessageBox(NULL, "The WinVNC service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
}
// Now remove the service from the SCM
if (DeleteService(hservice))
{
if (!silent) vncTimedMsgBox::Do("The WinVNC service has been unregistered", szAppName, MB_ICONINFORMATION | MB_OK);
}
else
{
DWORD error = GetLastError();
if (error == ERROR_SERVICE_MARKED_FOR_DELETE)
if (!silent) MessageBox(NULL, "The WinVNC service is already marked to be unregistered", szAppName, MB_ICONEXCLAMATION | MB_OK);
else
if (!silent) MessageBox(NULL, "The WinVNC service could not be unregistered", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
CloseServiceHandle(hservice);
}
else if (!silent)
MessageBox(NULL, "The WinVNC service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
CloseServiceHandle(hsrvmanager);
}
else if (!silent)
MessageBox(NULL, "The Service Control Manager could not be contacted - the WinVNC service was not unregistered", szAppName, MB_ICONEXCLAMATION | MB_OK);
}
break;
};
return 0;
}

// USEFUL SERVICE SUPPORT ROUTINES, Service control routine
void WINAPI ServiceCtrl(DWORD ctrlcode)
{
// What control code have we been sent?
switch(ctrlcode)
{
case SERVICE_CONTROL_STOP: // STOP : The service must stop
g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStop();
break;
case SERVICE_CONTROL_INTERROGATE: // QUERY : Service control manager just wants to know our state
break;
default: // Control code not recognised
break;
}
// Tell the control manager what we're up to.
ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
}

// Service manager status reporting
BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint)
{
static DWORD checkpoint = 1;
BOOL result = TRUE;
// If we're in the start state then we don't want the control manager
// sending us control messages because they'll confuse us.
if (state == SERVICE_START_PENDING)
g_srvstatus.dwControlsAccepted = 0;
else
g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
// Save the new status we've been given
g_srvstatus.dwCurrentState = state;
g_srvstatus.dwWin32ExitCode = exitcode;
g_srvstatus.dwWaitHint = waithint;
// Update the checkpoint variable to let the SCM know that we
// haven't died if requests take a long time
if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
g_srvstatus.dwCheckPoint = 0;
else
g_srvstatus.dwCheckPoint = checkpoint++;
// Tell the SCM our new status
if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus)))
LogErrorMsg("SetServiceStatus failed");
return result;
}

// Error reporting
void LogErrorMsg(char *message)
{
char msgbuff[256];
HANDLE heventsrc;
char * strings[2];
// Save the error code
g_error = GetLastError();
// Use event logging to log the error
heventsrc = RegisterEventSource(NULL, VNCSERVICENAME);
sprintf(msgbuff, "%.200s error: %d", VNCSERVICENAME, g_error);
strings[0] = msgbuff;
strings[1] = message;
if (heventsrc != NULL)
{
MessageBeep(MB_OK);
ReportEvent(
heventsrc, // handle of event source
EVENTLOG_ERROR_TYPE, // event type
0, // event category
0, // event ID
NULL, // current user's SID
2, // strings in 'strings'
0, // no bytes of raw data
(const char **)strings, // array of error strings
NULL); // no raw data
DeregisterEventSource(heventsrc);
}
}


  评论这张
 
阅读(2136)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018