📄 svcproc.cxx
字号:
{
return Current().WndProc(hWnd, msg, wParam, lParam);
}
static void SaveWindowPosition(HWND hWnd)
{
RECT r;
GetWindowRect(hWnd, &r);
PConfig cfg(ServiceSimulationSectionName);
cfg.SetInteger(WindowLeftKey, r.left);
cfg.SetInteger(WindowTopKey, r.top);
cfg.SetInteger(WindowRightKey, r.right);
cfg.SetInteger(WindowBottomKey, r.bottom);
}
LPARAM PServiceProcess::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
#ifdef _DEBUG
static DWORD allocationNumber;
#endif
switch (msg) {
case WM_CREATE :
controlWindow = hWnd;
break;
case WM_DESTROY :
if (debugWindow == (HWND)-1) {
PNotifyIconData nid(hWnd, NIF_TIP);
nid.Delete(); // This removes the systray icon
}
controlWindow = debugWindow = NULL;
PostQuitMessage(0);
break;
case WM_ENDSESSION :
if (wParam && (debugMode || lParam != ENDSESSION_LOGOFF) && debugWindow != (HWND)-1)
OnStop();
return 0;
case WM_MOVE :
if (debugWindow != NULL)
SaveWindowPosition(hWnd);
break;
case WM_SIZE :
if (debugWindow != NULL && debugWindow != (HWND)-1) {
SaveWindowPosition(hWnd);
MoveWindow(debugWindow, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
}
break;
case WM_INITMENUPOPUP :
{
int enableItems = MF_BYCOMMAND|(debugMode ? MF_ENABLED : MF_GRAYED);
for (int i = PSystemLog::Fatal; i < PSystemLog::NumLogLevels; i++) {
CheckMenuItem((HMENU)wParam, LogLevelBaseMenuID+i, MF_BYCOMMAND|MF_UNCHECKED);
EnableMenuItem((HMENU)wParam, LogLevelBaseMenuID+i, enableItems);
}
CheckMenuItem((HMENU)wParam, LogLevelBaseMenuID+GetLogLevel(), MF_BYCOMMAND|MF_CHECKED);
enableItems = MF_BYCOMMAND|(debugMode ? MF_GRAYED : MF_ENABLED);
EnableMenuItem((HMENU)wParam, SvcCmdBaseMenuID+SvcCmdStart, enableItems);
EnableMenuItem((HMENU)wParam, SvcCmdBaseMenuID+SvcCmdStop, enableItems);
EnableMenuItem((HMENU)wParam, SvcCmdBaseMenuID+SvcCmdPause, enableItems);
EnableMenuItem((HMENU)wParam, SvcCmdBaseMenuID+SvcCmdResume, enableItems);
DWORD start, finish;
if (debugWindow != NULL && debugWindow != (HWND)-1)
SendMessage(debugWindow, EM_GETSEL, (WPARAM)&start, (LPARAM)&finish);
else
start = finish = 0;
enableItems = MF_BYCOMMAND|(start == finish ? MF_GRAYED : MF_ENABLED);
EnableMenuItem((HMENU)wParam, CopyMenuID, enableItems);
EnableMenuItem((HMENU)wParam, CutMenuID, enableItems);
EnableMenuItem((HMENU)wParam, DeleteMenuID, enableItems);
enableItems = MF_BYCOMMAND|(IsServiceRunning(this) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem((HMENU)wParam, ControlMenuID, enableItems);
break;
}
case WM_COMMAND :
switch (wParam) {
case ExitMenuID :
DestroyWindow(hWnd);
break;
case ControlMenuID :
if (IsServiceRunning(this))
OnControl();
break;
case HideMenuID :
ShowWindow(hWnd, SW_HIDE);
break;
#if PMEMORY_CHECK
case MarkMenuID :
allocationNumber = PMemoryHeap::GetAllocationRequest();
break;
case DumpMenuID :
PMemoryHeap::DumpObjectsSince(allocationNumber);
break;
case StatsMenuID :
PMemoryHeap::DumpStatistics();
break;
case ValidateMenuID :
PMemoryHeap::ValidateHeap();
break;
#endif
case CopyMenuID :
if (debugWindow != NULL && debugWindow != (HWND)-1)
SendMessage(debugWindow, WM_COPY, 0, 0);
break;
case CutMenuID :
if (debugWindow != NULL && debugWindow != (HWND)-1)
SendMessage(debugWindow, WM_CUT, 0, 0);
break;
case DeleteMenuID :
if (debugWindow != NULL && debugWindow != (HWND)-1)
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -