📄 svcproc.cxx
字号:
SendMessage(debugWindow, WM_CLEAR, 0, 0);
break;
case SelectAllMenuID :
if (debugWindow != NULL && debugWindow != (HWND)-1)
SendMessage(debugWindow, EM_SETSEL, 0, -1);
break;
case OutputToMenuID :
if (debugWindow != NULL && debugWindow != (HWND)-1) {
char fileBuffer[_MAX_PATH];
OPENFILENAME fileDlgInfo;
memset(&fileDlgInfo, 0, sizeof(fileDlgInfo));
fileDlgInfo.lStructSize = sizeof(fileDlgInfo);
fileDlgInfo.hwndOwner = hWnd;
fileDlgInfo.hInstance = hInstance;
fileBuffer[0] = '\0';
fileDlgInfo.lpstrFile = fileBuffer;
char customFilter[100];
strcpy(customFilter, "All Files");
memcpy(&customFilter[strlen(customFilter)+1], "*.*\0", 5);
fileDlgInfo.lpstrCustomFilter = customFilter;
fileDlgInfo.nMaxCustFilter = sizeof(customFilter);
fileDlgInfo.nMaxFile = sizeof(fileBuffer);
fileDlgInfo.Flags = OFN_ENABLEHOOK|OFN_HIDEREADONLY|OFN_NOVALIDATE|OFN_EXPLORER|OFN_CREATEPROMPT;
fileDlgInfo.lCustData = (DWORD)this;
if (GetSaveFileName(&fileDlgInfo)) {
if (systemLogFileName != fileBuffer) {
systemLogFileName = fileBuffer;
PFile::Remove(systemLogFileName);
PConfig cfg(ServiceSimulationSectionName);
cfg.SetString(SystemLogFileNameKey, systemLogFileName);
DebugOutput("Sending all system log output to \"" + systemLogFileName + "\".\n");
PError << "Logging started for \"" << GetName() << "\" version " << GetVersion(TRUE) << endl;
}
}
}
break;
case WindowOutputMenuID :
if (!systemLogFileName) {
PError << "Logging stopped." << endl;
DebugOutput("System log output to \"" + systemLogFileName + "\" stopped.\n");
systemLogFileName = PString();
PConfig cfg(ServiceSimulationSectionName);
cfg.SetString(SystemLogFileNameKey, "");
}
break;
default :
if (wParam >= LogLevelBaseMenuID+PSystemLog::Fatal && wParam < LogLevelBaseMenuID+PSystemLog::NumLogLevels) {
SetLogLevel((PSystemLog::Level)(wParam-LogLevelBaseMenuID));
#if PTRACING
PTrace::SetLevel(wParam-LogLevelBaseMenuID-PSystemLog::Warning);
#endif
}
else if (wParam >= SvcCmdBaseMenuID && wParam < SvcCmdBaseMenuID+NumSvcCmds) {
const char * cmdname = ServiceCommandNames[wParam-SvcCmdBaseMenuID];
if (wParam == SvcCmdBaseMenuID+SvcCmdVersion ||
MessageBox(hWnd, cmdname & GetName() & "?", GetName(),
MB_ICONQUESTION|MB_YESNO) == IDYES)
ProcessCommand(cmdname);
}
}
break;
// Notification of event over sysTray icon
case UWM_SYSTRAY :
switch (lParam) {
case WM_MOUSEMOVE :
// update status of process for tool tips if no buttons down
if (wParam == SYSTRAY_ICON_ID) {
PNotifyIconData nid(hWnd, NIF_TIP,
GetName() & (IsServiceRunning(this) ? "is" : "not") & "running.");
nid.Modify(); // Modify tooltip
}
break;
// Click on icon - display message
case WM_LBUTTONDBLCLK :
if (IsServiceRunning(this))
OnControl();
else {
SetForegroundWindow(hWnd); // Our MessageBox pops up in front
MessageBox(hWnd, "Service is not running!", GetName(), MB_TASKMODAL);
}
break;
// Popup menu
case WM_RBUTTONUP :
POINT pt;
GetCursorPos(&pt);
HMENU menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, ControlMenuID, "&Open Properties");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdVersion, "&Version");
if (IsServiceRunning(this)) {
MENUITEMINFO inf;
inf.cbSize = sizeof(inf);
inf.fMask = MIIM_STATE;
inf.fState = MFS_DEFAULT;
SetMenuItemInfo(menu, ControlMenuID, FALSE, &inf);
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdStop, "&Stop Service");
}
else {
EnableMenuItem(menu, ControlMenuID, MF_GRAYED);
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdStart, "&Start Service");
}
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdNoTray, "&Tray Icon");
CheckMenuItem(menu, SvcCmdBaseMenuID+SvcCmdNoTray,
TrayIconRegistry(this, CheckTrayIcon) ? MF_CHECKED : MF_UNCHECKED);
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, ExitMenuID, "&Close");
/* SetForegroundWindow and the ensuing null PostMessage is a
workaround for a Windows 95 bug (see MSKB article Q135788,
http://www.microsoft.com/kb/articles/q135/7/88.htm, I think).
In typical Microsoft style this bug is listed as "by design".
SetForegroundWindow also causes our MessageBox to pop up in front
of any other application's windows. */
SetForegroundWindow(hWnd);
/* We specifiy TPM_RETURNCMD, so TrackPopupMenu returns the menu
selection instead of returning immediately and our getting a
WM_COMMAND with the selection. You don't have to do it this way.
*/
WndProc(hWnd, WM_COMMAND, TrackPopupMenu(menu, // Popup menu to track
TPM_RETURNCMD | // Return menu code
TPM_RIGHTBUTTON, // Track right mouse button?
pt.x, pt.y, // screen coordinates
0, // reserved
hWnd, // owner
NULL), // LPRECT user can click in without dismissing menu
0);
PostMessage(hWnd, 0, 0, 0); // see above
DestroyMenu(menu); // Delete loaded menu and reclaim its resources
break;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
void PServiceProcess::DebugOutput(const char * out)
{
if (controlWindow == NULL)
return;
if (debugWindow == NULL || debugWindow == (HWND)-1) {
for (PINDEX i = 0; i < 3; i++) {
const char * tab = strchr(out, '\t');
if (tab == NULL)
break;
out = tab+1;
}
MessageBox(controlWindow, out, GetName(), MB_TASKMODAL);
return;
}
if (!IsWindowVisible(controlWindow))
ShowWindow(controlWindow, SW_SHOWDEFAULT);
int len = strlen(out);
int max = isWin95 ? 32000 : 128000;
while (GetWindowTextLength(debugWindow)+len >= max) {
SendMessage(debugWindow, WM_SETREDRAW, FALSE, 0);
DWORD start, finish;
SendMessage(debugWindow, EM_GETSEL, (WPARAM)&start, (LPARAM)&finish);
SendMessage(debugWindow, EM_SETSEL, 0,
SendMessage(debugWindow, EM_LINEINDEX, 1, 0));
SendMessage(debugWindow, EM_REPLACESEL, FALSE, (DWORD)"");
SendMessage(debugWindow, EM_SETSEL, start, finish);
SendMessage(debugWindow, WM_SETREDRAW, TRUE, 0);
}
SendMessage(debugWindow, EM_SETSEL, max, max);
char * lf;
char * prev = (char *)out;
while ((lf = strchr(prev, '\n')) != NULL) {
if (*(lf-1) == '\r')
prev = lf+1;
else {
*lf++ = '\0';
SendMessage(debugWindow, EM_REPLACESEL, FALSE, (DWORD)out);
SendMessage(debugWindow, EM_REPLACESEL, FALSE, (DWORD)"\r\n");
out = (const char *)lf;
prev = lf;
}
}
if (*out != '\0')
SendMessage(debugWindow, EM_REPLACESEL, FALSE, (DWORD)out);
}
void PServiceProcess::StaticMainEntry(DWORD argc, LPTSTR * argv)
{
Current().MainEntry(argc, argv);
}
void PServiceProcess::MainEntry(DWORD argc, LPTSTR * argv)
{
// SERVICE_STATUS members that don't change
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwServiceSpecificExitCode = 0;
// register our service control handler:
statusHandle = RegisterServiceCtrlHandler(GetName(), StaticControlEntry);
if (statusHandle == NULL)
return;
// report the status to Service Control Manager.
if (!ReportStatus(SERVICE_START_PENDING, NO_ERROR, 1, 20000))
return;
// create the stop event object. The control handler function signals
// this event when it receives the "stop" control code.
terminationEvent = CreateEvent(NULL, TRUE, FALSE, (const char *)GetName());
if (terminationEvent == NULL)
return;
startedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (startedEvent == NULL)
return;
GetArguments().SetArgs(argc, argv);
// start the thread that performs the work of the service.
threadHandle = (HANDLE)_beginthread(StaticThreadEntry, 0, this);
if (threadHandle != (HANDLE)-1) {
while (WaitForSingleObject(startedEvent, 10000) == WAIT_TIMEOUT) {
if (!ReportStatus(SERVICE_START_PENDING, NO_ERROR, 1, 20000))
return;
}
// Wait here for the end
WaitForSingleObject(terminationEvent, INFINITE);
}
CloseHandle(startedEvent);
CloseHandle(terminationEvent);
ReportStatus(SERVICE_STOPPED, 0);
}
void PServiceProcess::StaticThreadEntry(void * arg)
{
((PServiceProcess *)arg)->ThreadEntry();
}
void PServiceProcess::ThreadEntry()
{
activeThreadMutex.Wait();
threadId = GetCurrentThreadId();
threadHandle = GetCurrentThread();
activeThreads.SetAt(threadId, this);
activeThreadMutex.Signal();
SetTerminationValue(1);
if (OnStart()) {
if (!debugMode)
SetEvent(startedEvent);
ReportStatus(SERVICE_RUNNING);
SetTerminationValue(0);
Main();
ReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 1, 30000);
}
SetEvent(terminationEvent);
}
void PServiceProcess::StaticControlEntry(DWORD code)
{
Current().ControlEntry(code);
}
void PServiceProcess::ControlEntry(DWORD code)
{
switch (code) {
case SERVICE_CONTROL_PAUSE : // Pause the service if it is running.
if (status.dwCurrentState != SERVICE_RUNNING)
ReportStatus(status.dwCurrentState);
else {
if (OnPause())
ReportStatus(SERVICE_PAUSED);
}
break;
case SERVICE_CONTROL_CONTINUE : // Resume the paused service.
if (status.dwCurrentState == SERVICE_PAUSED)
OnContinue();
ReportStatus(status.dwCurrentState);
break;
case SERVICE_CONTROL_STOP : // Stop the service.
// Report the status, specifying the checkpoint and waithint, before
// setting the termination event.
ReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 1, 30000);
OnStop();
SetEvent(terminationEvent);
break;
case SERVICE_CONTROL_INTERROGATE : // Update the service status.
default :
ReportStatus(status.dwCurrentState);
}
}
BOOL PServiceProcess::ReportStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint)
{
// Disable control requests until the service is started.
if (dwCurrentState == SERVICE_START_PENDING)
status.dwControlsAccepted = 0;
else
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
// These SERVICE_STATUS members are set from parameters.
status.dwCurrentState = dwCurrentState;
status.dwWin32ExitCode = dwWin32ExitCode;
status.dwCheckPoint = dwCheckPoint;
status.dwWaitHint = dwWaitHint;
if (debugMode || isWin95)
return TRUE;
// Report the status of the service to the service control manager.
if (SetServiceStatus(statusHandle, &status))
return TRUE;
// If an error occurs, stop the service.
PSystemLog::Output(PSystemLog::Error, "SetServiceStatus failed");
return FALSE;
}
void PServiceProcess::OnStop()
{
}
BOOL PServiceProcess::OnPause()
{
SuspendThread(threadHandle);
return TRUE;
}
void PServiceProcess::OnContinue()
{
ResumeThread(threadHandle);
}
void PServiceProcess::OnControl()
{
}
class ServiceManager
{
public:
ServiceManager() { error = 0; }
virtual BOOL Create(PServiceProcess * svc) = 0;
virtual BOOL Delete(PServiceProcess * svc) = 0;
virtual BOOL Start(PServiceProcess * svc) = 0;
virtual BOOL Stop(PServiceProcess * svc) = 0;
virtual BOOL Pause(PServiceProcess * svc) = 0;
virtual BOOL Resume(PServiceProcess * svc) = 0;
DWORD GetError() const { return error; }
protected:
DWORD error;
};
class Win95_ServiceManager : public ServiceManager
{
public:
virtual BOOL Create(PServiceProcess * svc);
virtual BOOL Delete(PServiceProcess * svc);
virtual BOOL Start(PServiceProcess * svc);
virtual BOOL Stop(PServiceProcess * svc);
virtual BOOL Pause(PServiceProcess * svc);
virtual BOOL Resume(PServiceProcess * svc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -