📄 svcproc.cxx
字号:
else
*out << "Debug" << (level-Info);
}
*out << '\t' << msg;
if (level < Info && err != 0)
*out << " - error = " << err << endl;
else if (msg[0] == '\0' || msg[strlen(msg)-1] != '\n')
*out << endl;
if (process.systemLogFileName.IsEmpty())
process.DebugOutput(*(PStringStream*)out);
delete out;
ReleaseMutex(mutex);
SetLastError(0);
}
else {
// Use event logging to log the error.
HANDLE hEventSource = RegisterEventSource(NULL, process.GetName());
if (hEventSource == NULL)
return;
PString threadName;
PThread * thread = PThread::Current();
if (thread != NULL)
threadName = thread->GetThreadName();
else
threadName.sprintf("%u", GetCurrentThreadId());
char thrdbuf[16];
if (threadName.IsEmpty())
sprintf(thrdbuf, "0x%08X", thread);
else {
strncpy(thrdbuf, threadName, sizeof(thrdbuf)-1);
thrdbuf[sizeof(thrdbuf)-1] = '\0';
}
char errbuf[25];
if (level > StdError && level < Info && err != 0)
::sprintf(errbuf, "Error code = %d", err);
else
errbuf[0] = '\0';
LPCTSTR strings[4];
strings[0] = thrdbuf;
strings[1] = msg;
strings[2] = errbuf;
strings[3] = level != Fatal ? "" : " Program aborted.";
static const WORD levelType[Info+1] = {
EVENTLOG_INFORMATION_TYPE,
EVENTLOG_ERROR_TYPE,
EVENTLOG_ERROR_TYPE,
EVENTLOG_WARNING_TYPE
};
ReportEvent(hEventSource, // handle of event source
(WORD)(level < Info ? levelType[level+1]
: EVENTLOG_INFORMATION_TYPE), // event type
(WORD)(level+1), // event category
0x1000, // event ID
NULL, // current user's SID
PARRAYSIZE(strings), // number of strings
0, // no bytes of raw data
strings, // array of error strings
NULL); // no raw data
DeregisterEventSource(hEventSource);
}
}
int PSystemLog::Buffer::overflow(int c)
{
if (pptr() >= epptr()) {
#if PMEMORY_CHECK
BOOL previousIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
#endif
int ppos = pptr() - pbase();
char * newptr = string.GetPointer(string.GetSize() + 10);
setp(newptr, newptr + string.GetSize() - 1);
pbump(ppos);
#if PMEMORY_CHECK
PMemoryHeap::SetIgnoreAllocations(previousIgnoreAllocations);
#endif
}
if (c != EOF) {
*pptr() = (char)c;
pbump(1);
}
return 0;
}
int PSystemLog::Buffer::underflow()
{
return EOF;
}
int PSystemLog::Buffer::sync()
{
Level logLevel;
if (log->width() == 0 || (PTrace::GetOptions()&PTrace::SystemLogStream) == 0)
logLevel = log->logLevel;
else {
// Trace system sets the ios stream width as the last thing it does before
// doing a flush, which gets us here. SO now we can get a PTRACE looking
// exactly like a PSYSTEMLOG of appropriate level.
unsigned traceLevel = log->width() -1 + PSystemLog::Warning;
log->width(0);
if (traceLevel >= PSystemLog::NumLogLevels)
traceLevel = PSystemLog::NumLogLevels-1;
logLevel = (Level)traceLevel;
}
PSystemLog::Output(logLevel, string);
#if PMEMORY_CHECK
BOOL previousIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(TRUE);
#endif
string.SetSize(10);
char * base = string.GetPointer();
*base = '\0';
setp(base, base + string.GetSize() - 1);
#if PMEMORY_CHECK
PMemoryHeap::SetIgnoreAllocations(previousIgnoreAllocations);
#endif
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// PServiceProcess
PServiceProcess::PServiceProcess(const char * manuf, const char * name,
WORD major, WORD minor, CodeStatus stat, WORD build)
: PProcess(manuf, name, major, minor, stat, build),
systemLogFileName(GetFile().GetDirectory() + GetName() + " Log.TXT")
{
controlWindow = debugWindow = NULL;
currentLogLevel = PSystemLog::Warning;
}
PServiceProcess & PServiceProcess::Current()
{
PServiceProcess & process = (PServiceProcess &)PProcess::Current();
PAssert(PIsDescendant(&process, PServiceProcess), "Not a service!");
return process;
}
const char * PServiceProcess::GetServiceDependencies() const
{
return "EventLog\0";
}
BOOL PServiceProcess::IsServiceProcess() const
{
return TRUE;
}
static BOOL IsServiceRunning(PServiceProcess * svc)
{
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, svc->GetName());
if (hEvent == NULL)
return ::GetLastError() == ERROR_ACCESS_DENIED;
CloseHandle(hEvent);
return TRUE;
}
int PServiceProcess::_main(void * arg)
{
#if PMEMORY_CHECK
PMemoryHeap::SetIgnoreAllocations(TRUE);
#endif
PSetErrorStream(new PSystemLog(PSystemLog::StdError));
PTrace::SetStream(new PSystemLog(PSystemLog::Debug3));
PTrace::ClearOptions(PTrace::FileAndLine);
PTrace::SetOptions(PTrace::SystemLogStream);
PTrace::SetLevel(4);
#if PMEMORY_CHECK
PMemoryHeap::SetIgnoreAllocations(FALSE);
#endif
hInstance = (HINSTANCE)arg;
OSVERSIONINFO verinfo;
verinfo.dwOSVersionInfoSize = sizeof(verinfo);
GetVersionEx(&verinfo);
switch (verinfo.dwPlatformId) {
case VER_PLATFORM_WIN32_NT :
isWin95 = FALSE;
break;
case VER_PLATFORM_WIN32_WINDOWS :
isWin95 = TRUE;
break;
default :
PError << "Unsupported Win32 platform type!" << endl;
return 1;
}
debugMode = arguments.GetCount() > 0 && stricmp(arguments[0], "Debug") == 0;
currentLogLevel = debugMode ? PSystemLog::Info : PSystemLog::Warning;
if (!debugMode && arguments.GetCount() > 0) {
for (PINDEX a = 0; a < arguments.GetCount(); a++)
ProcessCommand(arguments[a]);
if (controlWindow == NULL || controlWindow == (HWND)-1)
return GetTerminationValue();
if (debugWindow != NULL && debugWindow != (HWND)-1) {
::SetLastError(0);
PError << "Close window or select another command from the Control menu.\n" << endl;
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) != 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return GetTerminationValue();
}
if (!debugMode && !isWin95) {
static SERVICE_TABLE_ENTRY dispatchTable[] = {
{ "", PServiceProcess::StaticMainEntry },
{ NULL, NULL }
};
dispatchTable[0].lpServiceName = (char *)(const char *)GetName();
if (StartServiceCtrlDispatcher(dispatchTable))
return GetTerminationValue();
PSystemLog::Output(PSystemLog::Fatal, "StartServiceCtrlDispatcher failed.");
MessageBox(NULL, "Not run as a service!", GetName(), MB_TASKMODAL);
return 1;
}
if (!CreateControlWindow(debugMode))
return 1;
if (IsServiceRunning(this)) {
MessageBox(NULL, "Service already running", GetName(), MB_TASKMODAL);
return 3;
}
if (debugMode) {
::SetLastError(0);
PError << "Service simulation started for \"" << GetName() << "\" version " << GetVersion(TRUE) << "\n"
"Close window to terminate.\n" << endl;
}
terminationEvent = CreateEvent(NULL, TRUE, FALSE, GetName());
PAssertOS(terminationEvent != NULL);
threadHandle = (HANDLE)_beginthread(StaticThreadEntry, 0, this);
PAssertOS(threadHandle != (HANDLE)-1);
SetTerminationValue(0);
MSG msg;
msg.message = WM_QUIT+1; //Want somethingthat is not WM_QUIT
do {
switch (MsgWaitForMultipleObjects(1, &terminationEvent,
FALSE, INFINITE, QS_ALLINPUT)) {
case WAIT_OBJECT_0+1 :
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message != WM_QUIT) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
break;
default :
// This is a work around for '95 coming up with an erroneous error
if (::GetLastError() == ERROR_INVALID_HANDLE &&
WaitForSingleObject(terminationEvent, 0) == WAIT_TIMEOUT)
break;
// Else fall into next case
case WAIT_OBJECT_0 :
if (!debugMode || controlWindow == NULL)
msg.message = WM_QUIT;
else {
PError << "nService simulation stopped for \"" << GetName() << "\".\n\n"
"Close window to terminate.\n" << endl;
ResetEvent(terminationEvent);
}
}
} while (msg.message != WM_QUIT);
if (controlWindow != NULL)
DestroyWindow(controlWindow);
// Set thread ID for process to this thread
activeThreadMutex.Wait();
activeThreads.SetAt(threadId, NULL);
threadId = GetCurrentThreadId();
threadHandle = GetCurrentThread();
activeThreads.SetAt(threadId, this);
activeThreadMutex.Signal();
OnStop();
return GetTerminationValue();
}
enum {
ExitMenuID = 100,
HideMenuID,
ControlMenuID,
CopyMenuID,
CutMenuID,
DeleteMenuID,
SelectAllMenuID,
#if PMEMORY_CHECK
MarkMenuID,
DumpMenuID,
StatsMenuID,
ValidateMenuID,
#endif
OutputToMenuID,
WindowOutputMenuID,
SvcCmdBaseMenuID = 1000,
LogLevelBaseMenuID = 2000
};
static const char ServiceSimulationSectionName[] = "Service Simulation Parameters";
static const char WindowLeftKey[] = "Window Left";
static const char WindowTopKey[] = "Window Top";
static const char WindowRightKey[] = "Window Right";
static const char WindowBottomKey[] = "Window Bottom";
static const char SystemLogFileNameKey[] = "System Log File Name";
BOOL PServiceProcess::CreateControlWindow(BOOL createDebugWindow)
{
if (controlWindow != NULL)
return TRUE;
WNDCLASS wclass;
wclass.style = CS_HREDRAW|CS_VREDRAW;
wclass.lpfnWndProc = (WNDPROC)StaticWndProc;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hInstance = hInstance;
wclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ICON_RESID));
wclass.hCursor = NULL;
wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wclass.lpszMenuName = NULL;
wclass.lpszClassName = GetName();
if (RegisterClass(&wclass) == 0)
return FALSE;
HMENU menubar = CreateMenu();
HMENU menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, OutputToMenuID, "&Output To...");
AppendMenu(menu, MF_STRING, WindowOutputMenuID, "&Output To Window");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, ControlMenuID, "&Control");
AppendMenu(menu, MF_STRING, HideMenuID, "&Hide");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdVersion, "&Version");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
#if PMEMORY_CHECK
AppendMenu(menu, MF_STRING, MarkMenuID, "&Mark Memory");
AppendMenu(menu, MF_STRING, DumpMenuID, "&Dump Memory");
AppendMenu(menu, MF_STRING, StatsMenuID, "&Statistics");
AppendMenu(menu, MF_STRING, ValidateMenuID, "&Validate Heap");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
#endif
AppendMenu(menu, MF_STRING, ExitMenuID, "E&xit");
AppendMenu(menubar, MF_POPUP, (UINT)menu, "&File");
menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, CopyMenuID, "&Copy");
AppendMenu(menu, MF_STRING, CutMenuID, "C&ut");
AppendMenu(menu, MF_STRING, DeleteMenuID, "&Delete");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, SelectAllMenuID, "&Select All");
AppendMenu(menubar, MF_POPUP, (UINT)menu, "&Edit");
menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdInstall, "&Install");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdRemove, "&Remove");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdDeinstall, "&Deinstall");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdStart, "&Start");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdStop, "S&top");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdPause, "&Pause");
AppendMenu(menu, MF_STRING, SvcCmdBaseMenuID+SvcCmdResume, "R&esume");
AppendMenu(menubar, MF_POPUP, (UINT)menu, "&Control");
menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Fatal, "&Fatal Error");
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Error, "&Error");
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Warning, "&Warning");
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Info, "&Information");
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Debug, "&Debug");
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Debug2, "Debug &2");
AppendMenu(menu, MF_STRING, LogLevelBaseMenuID+PSystemLog::Debug3, "Debug &3");
AppendMenu(menubar, MF_POPUP, (UINT)menu, "&Log Level");
if (CreateWindow(GetName(),
GetName(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
menubar,
hInstance,
NULL) == NULL)
return FALSE;
if (createDebugWindow && debugWindow == NULL) {
PConfig cfg(ServiceSimulationSectionName);
int l = cfg.GetInteger(WindowLeftKey, -1);
int t = cfg.GetInteger(WindowTopKey, -1);
int r = cfg.GetInteger(WindowRightKey, -1);
int b = cfg.GetInteger(WindowBottomKey, -1);
if (l > 0 && t > 0 && r > 0 && b > 0)
SetWindowPos(controlWindow, NULL, l, t, r-l, b-t, 0);
debugWindow = CreateWindow("edit",
"",
WS_CHILD|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE|WS_BORDER|
ES_MULTILINE|ES_READONLY,
0, 0, 0, 0,
controlWindow,
(HMENU)10,
hInstance,
NULL);
SendMessage(debugWindow, EM_SETLIMITTEXT, isWin95 ? 32000 : 128000, 0);
DWORD TabStops[] = {
DATE_WIDTH,
DATE_WIDTH+THREAD_WIDTH,
DATE_WIDTH+THREAD_WIDTH+LEVEL_WIDTH,
DATE_WIDTH+THREAD_WIDTH+LEVEL_WIDTH+PROTO_WIDTH,
DATE_WIDTH+THREAD_WIDTH+LEVEL_WIDTH+PROTO_WIDTH+ACTION_WIDTH,
DATE_WIDTH+THREAD_WIDTH+LEVEL_WIDTH+PROTO_WIDTH+ACTION_WIDTH+32 // Standard tab width
};
SendMessage(debugWindow, EM_SETTABSTOPS, PARRAYSIZE(TabStops), (LPARAM)(LPDWORD)TabStops);
systemLogFileName = cfg.GetString(SystemLogFileNameKey);
if (!systemLogFileName) {
PFile::Remove(systemLogFileName);
DebugOutput("Sending all system log output to \"" + systemLogFileName + "\".\n");
}
}
return TRUE;
}
LPARAM WINAPI PServiceProcess::StaticWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -