📄 vncservice.cpp
字号:
// Static routine to simulate Ctrl-Alt-Del locallyBOOLvncService::SimulateCtrlAltDel(){ vnclog.Print(LL_ALL, VNCLOG("preparing to generate ctrl-alt-del\n")); // Are we running on NT? if (IsWinNT()) { vnclog.Print(LL_ALL, VNCLOG("spawn ctrl-alt-del thread...\n")); // *** This is an unpleasant hack. Oh dear. // I simulate CtrAltDel by posting a WM_HOTKEY message to all // the windows on the Winlogon desktop. // This requires that the current thread is part of the Winlogon desktop. // But the current thread has hooks set & a window open, so it can't // switch desktops, so I instead spawn a new thread & let that do the work... omni_thread *thread = omni_thread::create(SimulateCtrlAltDelThreadFn); if (thread == NULL) return FALSE; thread->join(NULL); return TRUE; } return TRUE;}// Static routine to lock a 2K or above workstationBOOLvncService::LockWorkstation(){ if (!IsWinNT()) { vnclog.Print(LL_INTERR, VNCLOG("unable to lock workstation - not NT\n")); return FALSE; } vnclog.Print(LL_ALL, VNCLOG("locking workstation\n")); // Load the user32 library HMODULE user32 = LoadLibrary("user32.dll"); if (!user32) { vnclog.Print(LL_INTERR, VNCLOG("unable to load User32 DLL (%u)\n"), GetLastError()); return FALSE; } // Get the LockWorkstation function typedef BOOL (*LWProc) (); LWProc lockworkstation = (LWProc)GetProcAddress(user32, "LockWorkStation"); if (!lockworkstation) { vnclog.Print(LL_INTERR, VNCLOG("unable to locate LockWorkStation - requires Windows 2000 or above (%u)\n"), GetLastError()); FreeLibrary(user32); return FALSE; } // Attempt to lock the workstation BOOL result = (lockworkstation)(); if (!result) { vnclog.Print(LL_INTERR, VNCLOG("call to LockWorkstation failed\n")); FreeLibrary(user32); return FALSE; } FreeLibrary(user32); return result;}// Static routine to show the Properties dialog for a currently-running// copy of WinVNC, (usually a servicified version.)BOOLvncService::ShowProperties(){ // Post to the WinVNC menu window if (!PostToWinVNC(MENU_PROPERTIES_SHOW, 0, 0)) { MessageBox(NULL, "No existing instance of WinVNC could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE;}// Static routine to show the Default Properties dialog for a currently-running// copy of WinVNC, (usually a servicified version.)BOOLvncService::ShowDefaultProperties(){ // Post to the WinVNC menu window if (!PostToWinVNC(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0)) { MessageBox(NULL, "No existing instance of WinVNC could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE;}// Static routine to show the About dialog for a currently-running// copy of WinVNC, (usually a servicified version.)BOOLvncService::ShowAboutBox(){ // Post to the WinVNC menu window if (!PostToWinVNC(MENU_ABOUTBOX_SHOW, 0, 0)) { MessageBox(NULL, "No existing instance of WinVNC could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE;}// Static routine to tell a locally-running instance of the server// to connect out to a new clientBOOLvncService::PostAddNewClient(unsigned long ipaddress){ // Post to the WinVNC menu window if (!PostToWinVNC(MENU_ADD_CLIENT_MSG, 0, ipaddress)) { MessageBox(NULL, "No existing instance of WinVNC could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK); return FALSE; } return TRUE;}// SERVICE-MODE ROUTINES// 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 stateSERVICE_STATUS g_srvstatus; // current status of the serviceSERVICE_STATUS_HANDLE g_hstatus;DWORD g_error = 0;DWORD g_servicethread = NULL;char* g_errortext[256];// Forward defines of internal service functionsvoid 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 NOTBOOL g_servicemode = FALSE;BOOLvncService::RunningAsService(){ return g_servicemode;}BOOLvncService::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 NTBOOLvncService::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;}// ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGEBOOLvncService::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(%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(%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(%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 ROUTINEintvncService::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) { // Windows 95/98 case VER_PLATFORM_WIN32_WINDOWS: { // 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; // Windows NT case VER_PLATFORM_WIN32_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 ROUTINEvoid 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 WinVNCAppMainvoid 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 threadvoid 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 ROUTINEintvncService::ReinstallService() { RemoveService(1); InstallService(0); return 0;}intvncService::InstallService(BOOL silent){ const int pathlength = 2048; char path[pathlength];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -