⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 svcproc.cxx

📁 opal的ptlib c++源程序 可以从官方网站上下载
💻 CXX
📖 第 1 页 / 共 4 页
字号:
/*
 * svcproc.cxx
 *
 * Service process implementation for Win95 and WinNT
 *
 * Portable Windows Library
 *
 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Portable Windows Library.
 *
 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
 *
 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * $Revision: 19426 $
 * $Author: rjongbloed $
 * $Date: 2008-02-09 03:19:51 +0000 (Sat, 09 Feb 2008) $
 */

#include <ptlib.h>

#include <winuser.h>
#include <winnls.h>
#include <shellapi.h>
#include <commdlg.h>

#include <process.h>
#include <signal.h>
#include <fcntl.h>
#include <io.h>

#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"comdlg32.lib")

#ifdef __USE_STL__
#include <fstream>
#else
#include <fstream.h>
#endif

#include <ptlib/svcproc.h>


#define new PNEW


#define UWM_SYSTRAY (WM_USER + 1)
#define ICON_RESID 1
#define SYSTRAY_ICON_ID 1

static HINSTANCE hInstance;

#define DATE_WIDTH    72
#define THREAD_WIDTH  80
#define LEVEL_WIDTH   32
#define PROTO_WIDTH   40
#define ACTION_WIDTH  48

enum {
  SvcCmdTray,
  SvcCmdNoTray,
  SvcCmdVersion,
  SvcCmdInstall,
  SvcCmdRemove,
  SvcCmdStart,
  SvcCmdStop,
  SvcCmdPause,
  SvcCmdResume,
  SvcCmdDeinstall,
  SvcCmdNoWindow,
  NumSvcCmds
};

static const char * const ServiceCommandNames[NumSvcCmds] = {
  "Tray",
  "NoTray",
  "Version",
  "Install",
  "Remove",
  "Start",
  "Stop",
  "Pause",
  "Resume",
  "Deinstall",
  "NoWin"
};


static const char WindowLogOutput[] = "Window Log Output";
static const char DebuggerLogOutput[] = "Debugger Log Output";


class PNotifyIconData : public NOTIFYICONDATA {
  public:
    PNotifyIconData(HWND hWnd, UINT flags, const char * tip = NULL);
    void Add()    { Shell_NotifyIcon(NIM_ADD,    this); }
    void Delete() { Shell_NotifyIcon(NIM_DELETE, this); }
    void Modify() { Shell_NotifyIcon(NIM_MODIFY, this); }
};


PNotifyIconData::PNotifyIconData(HWND window, UINT flags, const char * tip)
{
  cbSize = sizeof(NOTIFYICONDATA);
  hWnd   = window;
  uID    = SYSTRAY_ICON_ID;
  uFlags = flags;
  if (tip != NULL) {
    strncpy(szTip, tip, sizeof(szTip)-1);
    szTip[sizeof(szTip)-1] = '\0';
    uFlags |= NIF_TIP;
  }
}


enum TrayIconRegistryCommand {
  AddTrayIcon,
  DelTrayIcon,
  CheckTrayIcon
};

static PBoolean TrayIconRegistry(PServiceProcess * svc, TrayIconRegistryCommand cmd)
{
  HKEY key;
  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                   "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
                   0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
    return PFalse;

  DWORD err = 1;
  DWORD type;
  DWORD len;
  PString str;
  switch (cmd) {
    case CheckTrayIcon :
      err = RegQueryValueEx(key, svc->GetName(), 0, &type, NULL, &len);
      break;

    case AddTrayIcon :
      str = "\"" + svc->GetFile() + "\" Tray";
      err = RegSetValueEx(key, svc->GetName(), 0, REG_SZ,
                         (LPBYTE)(const char *)str, str.GetLength() + 1);
      break;

    case DelTrayIcon :
      err = RegDeleteValue(key, (char *)(const char *)svc->GetName());
  }

  RegCloseKey(key);
  return err == ERROR_SUCCESS;
}



///////////////////////////////////////////////////////////////////////////////
// PSystemLog

void PSystemLog::Output(Level level, const char * msg)
{
  PServiceProcess & process = PServiceProcess::Current();
  if (level > process.GetLogLevel())
    return;

  DWORD err = ::GetLastError();

  if (process.isWin95 || process.controlWindow != NULL) {
    static HANDLE mutex = CreateMutex(NULL, PFalse, NULL);
    WaitForSingleObject(mutex, INFINITE);

    ostream * out;
    if (process.systemLogFileName == WindowLogOutput || process.systemLogFileName == DebuggerLogOutput)
      out = new PStringStream;
    else
      out = new ofstream(process.systemLogFileName, ios::app);

    PTime now;
    *out << now.AsString("yyyy/MM/dd hh:mm:ss.uuu\t");
    PThread * thread = PThread::Current();
    if (thread == NULL)
      *out << "ThreadID=0x"
           << setfill('0') << hex
           << setw(8) << GetCurrentThreadId()
           << setfill(' ') << dec;
    else {
      PString threadName = thread->GetThreadName();
      if (threadName.GetLength() <= 23)
        *out << setw(23) << threadName;
      else
        *out << threadName.Left(10) << "..." << threadName.Right(10);
    }

    *out << '\t';
    if (level < 0)
      *out << "Message";
    else {
      static const char * const levelName[4] = {
        "Fatal error",
        "Error",
        "Warning",
        "Info"
      };
      if (level < PARRAYSIZE(levelName))
        *out << levelName[level];
      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 == WindowLogOutput)
      process.DebugOutput(*(PStringStream*)out);
    else if (process.systemLogFileName == DebuggerLogOutput)
      OutputDebugStringA(*(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()) {
    PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;

    int ppos = pptr() - pbase();
    char * newptr = string.GetPointer(string.GetSize() + 10);
    setp(newptr, newptr + string.GetSize() - 1);
    pbump(ppos);
  }
  if (c != EOF) {
    *pptr() = (char)c;
    pbump(1);
  }

  return 0;
}


int PSystemLog::Buffer::underflow()
{
  return EOF;
}


int PSystemLog::Buffer::sync()
{
  Level logLevel = log->logLevel;

#if PTRACING
  if (log->width() != 0 &&(PTrace::GetOptions()&PTrace::SystemLogStream) != 0) {
    // 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;
  }
#endif

  PSystemLog::Output(logLevel, string);

  PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;

  string.SetSize(10);
  char * base = string.GetPointer();
  *base = '\0';
  setp(base, base + string.GetSize() - 1);
 
  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";
}


PBoolean PServiceProcess::IsServiceProcess() const
{
  return PTrue;
}


static PBoolean IsServiceRunning(PServiceProcess * svc)
{
  HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, PFalse, svc->GetName());
  if (hEvent == NULL)
    return ::GetLastError() == ERROR_ACCESS_DENIED;

  CloseHandle(hEvent);
  return PTrue;
}


int PServiceProcess::_main(void * arg)
{
  {
    PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;

    PSetErrorStream(new PSystemLog(PSystemLog::StdError));
#if PTRACING
    PTrace::SetStream(new PSystemLog(PSystemLog::Debug3));
    PTrace::ClearOptions(PTrace::FileAndLine);
    PTrace::SetOptions(PTrace::SystemLogStream);
    PTrace::SetLevel(4);
#endif
  }

  hInstance = (HINSTANCE)arg;

  OSVERSIONINFO verinfo;
  verinfo.dwOSVersionInfoSize = sizeof(verinfo);
  GetVersionEx(&verinfo);
  switch (verinfo.dwPlatformId) {
    case VER_PLATFORM_WIN32_NT :
      isWin95 = PFalse;
      break;
    case VER_PLATFORM_WIN32_WINDOWS :
      isWin95 = PTrue;
      break;
    default :

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -