천객만래 [千客萬來] (It has an interminable succession of visitors)

출처 :  http://msdn.microsoft.com/en-us/library/e305240e-9e11-4006-98cc-26f4932d2118(VS.85) 


VARIANT, BSTR & SAFEARRAY C++ Tutorial...

Introduction

Frustrated by the lack of good articles on the VARIANT data type, I decided to write this short introduction.

The VARIANT type is an all purpose data type used by IDispatch::Invoke both to transmit and receive parameters. It can hold numbers, strings, arrays, error values and IDispatch pointers. An XLL developer could consider the variant to be the Automation equivalent of the do everything Excel XLOPER data type.

Structure

Here is a simplified version of the VARIANT definition. For the full definition see this link.

struct tagVARIANT {
    VARTYPE vt; // unsigned short integer type code
    WORD wReserved1;
    WORD wReserved2;
    WORD wReserved3;
    union {
    //  C++ Type      Union Name   Type Tag                Basic Type
    //  --------      ----------   --------                ----------

        long          lVal;        // VT_I4                ByVal Long
        unsigned char bVal;        // VT_UI1               ByVal Byte
        short         iVal;        // VT_I2                ByVal Integer
        double        dblVal;      // VT_R8                ByVal Double
        VARIANT_BOOL  boolVal;     // VT_BOOL              ByVal Boolean
        SCODE         scode;       // VT_ERROR
        DATE          date;        // VT_DATE              ByVal Date
        BSTR          bstrVal;     // VT_BSTR              ByVal String
        IUnknown      *punkVal;    // VT_UNKNOWN 
        IDispatch     *pdispVal;   // VT_DISPATCH          ByVal Object
        SAFEARRAY     *parray;     // VT_ARRAY|*           ByVal array
        // A bunch of other types that don't matter here...
        VARIANT       *pvarVal;    // VT_BYREF|VT_VARIANT  ByRef Variant
        void          * byref;     // Generic ByRef        
    };
};

The variant type is 16 bytes in size.

[출처] variant|작성자 najira00

Posted by SB패밀리
[개발/API] 웹에 있는 파일크기 알아오기


DWORD GetHttpFileSize(LPCTSTR lpszUrl)
{
HINTERNET hInternet,hURL;
TCHAR buffer[32];
DWORD dwSize=32,dwFileSize;

// 인터넷 연결
hInternet=InternetOpen(TEXT(""), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
if (hInternet == NULL) return -1; // 인터넷 연결이 되지 않았으면 에러 리턴

// URL 오픈
hURL=InternetOpenUrl(hInternet, lpszUrl, NULL, 0, INTERNET_FLAG_TRANSFER_BINARY, 0);

// 오픈에 실패했을 경우 에러 리턴
if (hURL == NULL) { InternetCloseHandle(hInternet); return -1; }

// 핵심 함수인 HttpQueryInfo
HttpQueryInfo(hURL, HTTP_QUERY_CONTENT_LENGTH, buffer, &dwSize, 0);
dwFileSize = _ttoi(buffer);

InternetCloseHandle(hInternet);
InternetCloseHandle(hURL);

return dwFileSize;
}


Posted by SB패밀리
SHAppBarMessage 작업표시줄 정보 및 작업영역 구하기

SHAppBarMessage 함수
http://msdn.microsoft.com/en-us/library/bb762108(VS-85).aspx
How to find the edge of a task bar
http://support.microsoft.com/kb/179908/en-us
MinitorFromRect 함수
http://msdn.microsoft..com/en-us/library/dd145063(VS.85).aspx
GetMonitorInfo 함수
http://msdn.microsoft..com/en-us/library/dd144901(VS.85).aspx

1. 먼저 작업표시줄의 위치와 영역을 알아야.
SHAppBarMessage()함수 이용(파라메터: ABE_GETTASKBARPOS)

2. 작업표시줄 영역을 통해 모니터를 구한다.
MonitorFromRect() 함수

3. 모니터의 작업영역을 구한다.
GetMonitorInfo()함수

// shellapi.h (uEdge 값의 위치)
// #define ABE_LEFT 0
// #define ABE_TOP 1
// #define ABE_RIGHT 2
// #define ABE_BOTTOM 3

APPBARDATA abd;
abd.cbSize = sizeof(APPBARDATA);
abd.hWnd = GetSafeHwnd();
SHAppBarMessage(ABM_GETTASKBARPOS, &abd);
// taskbar 위치
UINT nTaskBarPos = abd.uEdge;
// taskbar 가 위치한 모니터의 핸들 얻어옴
HMONITOR hMonitor = MonitorFromRect(&(abd.rc), MONITOR_DEFAULTTOPPRIMARY);
// 모니터의 정보 (Working area)
MONITORINFO monitorinfo;
monitorinfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hMonitor, &monitorinfo);
// desktop working area
CRect rcDesktop = monitorInfo.rcWork;
Posted by SB패밀리


CRT(C 런타임) 라이브러리와 MFC(Microsoft Foundation Class) 라이브러리가 잘못된 순서로 링크되면 다음과 비슷한 LNK2005 오류가 발생할 수 있습니다. 

nafxcwd.lib(afxmem.obj) : 오류 LNK2005:
"void * __cdecl operator new(unsigned int)"(??2@YAPAXI@Z)이(가)
LIBCMTD.lib(new.obj)에 이미 정의되어 있습니다. 

nafxcwd.lib(afxmem.obj) : 오류 LNK2005:
"void __cdecl operator delete(void *)"(??3@YAXPAX@Z)이(가)
LIBCMTD.lib(dbgnew.obj)에 이미 정의되어 있습니다. 

nafxcwd.lib(afxmem.obj) : 오류 LNK2005:
"void * __cdecl operator new(unsigned int,int,char const *,int)"
(??2@YAPAXIHPBDH@Z)이(가) LIBCMTD.lib(dbgnew.obj)에 이미 정의되어 있습니다. 

mfcs40d.lib(dllmodul.obj): 오류 LNK2005: _DllMain@12이(가)
MSVCRTD.LIB (dllmain.obj)에 이미 정의되어 있습니다. 

mfcs42d.lib(dllmodul.obj): 오류 LNK2005: _DllMain@12이(가)
msvcrtd.lib(dllmain.obj)에 이미 정의되어 있습니다. 



원인
CRT 라이브러리는 new, delete 및 DllMain 함수에 대해 약한 외부 링크를 사용합니다. MFC 라이브러리에도 new, delete 및 DllMain 함수가 포함되어 있어 CRT 라이브러리 전에 MFC를 링크해야 합니다. 


해결 방법
이 문제를 해결할 수 있는 방법에는 두 가지가 있습니다. 첫 번째 해결 방법은 링커가 올바른 순서로 라이브러리를 강제 링크하도록 하는 것입니다. 두 번째 해결 방법은 문제를 일으키는 모듈을 찾아 해결하는 것입니다. 
해결 방법 1: 링커가 올바른 순서로 라이브러리를 강제 링크하는 방법
1. Project 메뉴에서 Settings을 눌러 Project Settings 대화 상자를 엽니다.
2. Settings For 뷰에서 링크 오류가 발생하는 프로젝트 구성을 선택(강조 표시)합니다.
3. Link 탭을 누릅니다.
4. Category 콤보 상자에서 INPUT을 선택합니다.
5. Ignore Libraries 입력란에 라이브러리 이름(예: Nafxcwd.lib Libcmtd.lib)을 입력합니다. 
   참고: 링커 명령줄은 /NOD:과 동일합니다.
6. Object/library Modules 입력란에 라이브러리 이름을 입력합니다. 이 이름은 반드시 해당 행의 처음 두 라이브러리(예: Nafxcwd.lib Libcmtd.lib)와 같은 순서대로 나열되어야 합니다.
Visual C++ .NET에서 이 옵션을 설정하려면 온라인 도움말의 Visual C++ 프로젝트 속성 설정 항목을 참조하십시오. 
해결 방법 2: 문제 모듈을 찾아 해결하는 방법
다음 단계를 수행하여 현재 라이브러리 링크 순서를 확인합니다. 
1. Project 메뉴에서 Settings을 눌러 Project Settings 대화 상자를 엽니다.
2. Settings For 뷰에서 링크 오류가 발생하는 프로젝트 구성을 선택(강조 표시)합니다.
3. Link 탭을 누릅니다.
4. Project Options 대화 상자에 다음을 입력합니다.
   /verbose:lib
5. 프로젝트를 다시 빌드합니다. 링크하는 과정에서 출력 창에 라이브러리가 표시됩니다.


현재 상태
이것은 의도적으로 설계된 동작입니다. 


추가 정보
MFC 라이브러리를 사용할 때는 MFC 라이브러리가 CRT 라이브러리 전에 링크되도록 해야 합니다. 이렇게 하려면 프로젝트에 있는 모든 파일이 직접(#include ) 또는 간접(#include )적으로 먼저 MsdevMfcIncludeAfx.h를 포함하도록 합니다. Afx.h 포함 파일은 #pragma 주석(lib,"") 지시어를 사용하여 라이브러리의 순서를 올바르게 조정합니다. 

원본 파일 확장명이 .c이거나 파일 확장명이 .cpp이지만 MFC를 사용하지 않는 경우 모듈 맨 위에 작은 헤더 파일(Forcelib.h)을 만들어 포함시킬 수 있습니다. 이 새로운 헤더가 라이브러리 검색 순서를 올바르게 합니다. 

Visual C++에는 이 헤더 파일이 들어 있지 않지만 다음 단계를 수행하여 이 파일을 쉽게 만들 수 있습니다. 
MsdevMfcIncludeAfx.h를 엽니다. 
#ifndef _AFX_NOFORCE_LIBS와 #endif //!_AFX_NOFORCE_LIBS 사이의 행을 선택합니다. 
선택 영역을 Windows 클립보드로 복사합니다. 
새 텍스트 파일을 만듭니다. 
클립보드 내용을 새 파일에 붙여넣습니다. 
파일을 MsdevMfcIncludeForcelib.h로 저장합니다.
Posted by SB패밀리

형 변환

char* to string



string temp_file;
char szPath[256] = "
C:\\Projects"
 

temp_file = string(szPath);
temp_file += string ("\\file.tmp");


string to char*


string temp_file = "\\file.tmp";
char szPath[256] = "
C:\\Projects"

strcat(szPath, temp_file.c_str());


 

  


















 
Posted by SB패밀리
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *replaceAll(char *s, const char *olds, const char *news);


void main(void){
  char s[] = "봉숭아 학당! 봉숭아 학당! 봉숭아 학당! 봉숭아 학당!";
  char *s2;

  printf("원본: %s\n", s);

  s2 = replaceAll(s, "봉숭아", "맹구");

  // 에러가 있으면 NULL 을 리턴. 에러가 없으면 결과 출력
  (s2 != NULL) ? printf("치환: %s\n", s2) : fputs("Replace String Error...\n", stderr);
}




char *replaceAll(char *s, const char *olds, const char *news) {
  char *result, *sr;
  size_t i, count = 0;
  size_t oldlen = strlen(olds); if (oldlen < 1) return s;
  size_t newlen = strlen(news);


  if (newlen != oldlen) {
    for (i = 0; s[i] != '\0';) {
      if (memcmp(&s[i], olds, oldlen) == 0) count++, i += oldlen;
      else i++;
    }
  } else i = strlen(s);


  result = (char *) malloc(i + 1 + count * (newlen - oldlen));
  if (result == NULL) return NULL;


  sr = result;
  while (*s) {
    if (memcmp(s, olds, oldlen) == 0) {
      memcpy(sr, news, newlen);
      sr += newlen;
      s  += oldlen;
    } else *sr++ = *s++;
  }
  *sr = '\0';

  return result;
}


출처:  
Posted by SB패밀리

에러 메세지 

" error LNK2019: __imp__PathRemoveFileSpecA@4 외부 기호 "

오류 error LNK2019: __imp__PathRemoveFileSpecA@4 외부 기호(참조 위치: "char * __cdecl GetAppPath(char *)" (?GetAppPath@@YAPADPAD@Z) 함수)에서 확인하지 못했습니다. Func.obj

는 해당 함수를 사용하는데 있어서 라이브러리가 링크되지 않아서 발생하는 에러메세지 입니다.

이 때에는 아래와 같은 library 링크를 추가해주면 됩니다.

#pragma comment(lib, "shlwapi.lib")


함수  PathAddBackslashA 이와 같은 것도 마찬가지
" error LNK2019:  __imp__PathAddBackslashA@4 외부 기호 "


Posted by SB패밀리

웹페이지의 존재여부를 확인하기 위한 팁입니다.
[VC++]
Check.cpp

CServer downloadServer;
CString strDownLoadStatus = downloadServer.RequestServer(strUrl.GetBuffer(0));

 

웹페이지의 존재여부를 확인하기 위한 팁입니다.
[C#]

주어진 URL에 해당하는 웹서버의 HTTP status code을 이용하여 확인한다.

 boolean exists(String URLName){
   try {
     HttpURLConnection.setFollowRedirects(true)
     HttpURLConnection con =
        (HttpURLConnection) new URL(URLName).openConnection();
        con.setRequestMethod("HEAD");
     if (con.getResponseCode() == HttpURLConnection.HTTP_OK)
        return true;
     }
   catch (Exception e) { }
     return false;
   }

Posted by SB패밀리

서비스 응용 프로그램의 일부로 존재할 서비스에 기본 클래스를 제공합니다. ServiceBase는 새 서비스 클래스를 만들 때 파생되어야 합니다.

네임스페이스: System.ServiceProcess
어셈블리: System.ServiceProcess(system.serviceprocess.dll)
언어 : C# / C++ 
// C# language example
C#
public class ServiceBase : Component
// C++ language example
C++
public ref class ServiceBase : public Component


설명


서비스 응용 프로그램에 있는 서비스 클래스를 정의할 때 ServiceBase에서 파생됩니다. 임의의 유용한 서비스가 OnStartOnStop 메서드를 재정의합니다. 추가 기능의 경우, 서비스 상태의 변경 내용에 대한 특정 동작을 사용하여 OnPauseOnContinue를 재정의할 수 있습니다.

서비스는 사용자 인터페이스를 지원하지 않는 장기 실행 파일이며, 사용자 계정으로 로그온한 상태에서는 실행되지 않습니다. 이 서비스는 컴퓨터에 로그온 중인 사용자 없이도 실행될 수 있습니다.

기본적으로 서비스는 System 계정으로 실행됩니다. System 계정은 Administrator 계정과는 다르며, System 계정의 권한은 변경할 수 없습니다. 또한 ServiceProcessInstaller를 사용하여 서비스를 실행할 사용자 계정을 지정할 수 있습니다.

실행 파일은 두 가지 이상의 서비스를 포함할 수 있지만 각 서비스에 대해 별도의 ServiceInstaller를 포함해야 합니다. ServiceInstaller 인스턴스는 서비스를 시스템에 등록합니다. 설치 관리자는 또한 각 서비스를 서비스 명령을 기록하는 데 사용할 수 있는 이벤트 로그와 연결합니다. 실행 파일에 있는 main() 함수는 실행할 서비스를 정의합니다. 서비스의 현재 작업 디렉터리는 실행 파일이 있는 디렉터리가 아니라 시스템 디렉터리입니다.

서비스가 시작되면 시스템에서는 실행 파일을 찾아 해당 파일 내에 포함된 서비스에 대한 OnStart 메서드를 실행시킵니다. 그러나 서비스를 실행하는 것과 실행 파일을 실행하는 것은 다릅니다. 실행 파일은 서비스를 로드만 하지만, 서비스는 서비스 제어 관리자를 통해 시작 및 중지하는 방법으로 액세스됩니다.

사용자가 서비스에서 시작 명령을 처음으로 호출하면 실행 파일에서 ServiceBase 파생 클래스의 생성자를 호출합니다. OnStart 명령 처리 메서드는 생성자가 실행된 직후에 호출됩니다. 생성자는 서비스가 처음 로드된 이후에 다시 실행되지 않으므로 생성자에서 수행한 프로세스와 OnStart에서 수행한 프로세스를 구분해야 합니다. OnStop을 사용하여 해제할 수 있는 리소스는 OnStart를 사용하여 만들어야 합니다. OnStop에서 리소스를 해제한 다음 서비스를 다시 시작하면 생성자에서 리소스를 만들 때 리소스가 제대로 만들어지지 않습니다.

SCM(서비스 제어 관리자)은 서비스와 상호 작용하는 방법을 제공합니다. SCM을 사용하여 시작, 중지, 일시 중지, 계속 또는 사용자 지정 명령을 서비스에 전달할 수 있습니다. SCM은 CanStopCanPauseAndContinue의 값을 사용하여 서비스에서 중지, 일시 중지 또는 계속 명령을 허용할지 여부를 결정합니다. 서비스 클래스에 있는 해당 속성인 CanStop 또는 CanPauseAndContinuetrue인 경우에만 SCM의 상황에 맞는 메뉴에서 중지, 일시 중지 및 계속을 사용할 수 있습니다. 명령을 사용할 수 있는 경우, 명령은 서비스에 전달되고 OnStop, OnPause 또는 OnContinue가 호출됩니다. CanStop, CanShutdown 또는 CanPauseAndContinuefalse이면 OnStop과 같은 해당 명령 처리 메서드가 구현되어 있어도 처리되지 않습니다.

SCM이 사용자 인터페이스를 사용하여 수행하는 작업을 ServiceController 클래스를 사용하여 프로그래밍 방식으로 수행할 수 있습니다. 콘솔에서 사용할 수 있는 작업을 자동화할 수 있습니다. CanStop, CanShutdown 또는 CanPauseAndContinuetrue이지만 해당 명령 처리 메서드(예: OnStop)를 구현하지 않은 경우 시스템에서 예외가 throw되고 해당 명령이 무시됩니다.

ServiceBase에 있는 OnStart, OnStop 또는 다른 메서드는 구현하지 않아도 됩니다. 그러나 서비스의 동작이 OnStart에 설명되어 있으므로 이 멤버를 재정의해야 합니다. 실행 파일의 main() 함수에 서비스의 이름을 설정해야 합니다. main()에 설정한 서비스 이름은 서비스 설치 관리자의 ServiceName 속성과 정확하게 일치해야 합니다.

InstallUtil.exe를 사용하여 시스템에 서비스를 설치할 수 있습니다.


예제


다음 예제에서는 ServiceBase 클래스에서 간단한 서비스 구현을 파생합니다. 이 서비스는 중지, 시작, 일시 중지, 계속 및 사용자 지정 명령을 포함한 다양한 서비스 명령을 처리합니다.

C#

// Turn on logging to the event log.
#define LOGEVENTS
using System;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ServiceSample
{
    // Define custom commands for the SimpleService.
    public enum SimpleServiceCustomCommands { StopWorker = 128, RestartWorker, CheckWorker };
    [StructLayout(LayoutKind.Sequential)]
    public struct SERVICE_STATUS
    {
        public int serviceType;
        public int currentState;
        public int controlsAccepted;
        public int win32ExitCode;
        public int serviceSpecificExitCode;
        public int checkPoint;
        public int waitHint;
    }
    public enum State
    {
        SERVICE_STOPPED = 0x00000001,
        SERVICE_START_PENDING = 0x00000002,
        SERVICE_STOP_PENDING = 0x00000003,
        SERVICE_RUNNING = 0x00000004,
        SERVICE_CONTINUE_PENDING = 0x00000005,
        SERVICE_PAUSE_PENDING = 0x00000006,
        SERVICE_PAUSED = 0x00000007,
    }
    // Define a simple service implementation.
    public class SimpleService : System.ServiceProcess.ServiceBase
    {
        private static int userCount = 0;
        private static ManualResetEvent pause = new ManualResetEvent(false);
        [DllImport("ADVAPI32.DLL", EntryPoint = "SetServiceStatus")]
        public static extern bool SetServiceStatus(
                        IntPtr hServiceStatus,
                        SERVICE_STATUS lpServiceStatus
                        );
        private SERVICE_STATUS myServiceStatus;
        private Thread workerThread = null;
        public SimpleService()
        {
            CanPauseAndContinue = true;
            CanHandleSessionChangeEvent = true;
            ServiceName = "SimpleService";
        }
        static void Main()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() +
                " - Service main method starting...");
#endif
            // Load the service into memory.
            System.ServiceProcess.ServiceBase.Run(new SimpleService());
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() +
                " - Service main method exiting...");
#endif
        }
        private void InitializeComponent()
        {
            // Initialize the operating properties for the service.
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.CanHandleSessionChangeEvent = true;
            this.ServiceName = "SimpleService";
        }
        // Start the service.
        protected override void OnStart(string[] args)
        {
            IntPtr handle = this.ServiceHandle;
            myServiceStatus.currentState = (int)State.SERVICE_START_PENDING;
            SetServiceStatus(handle, myServiceStatus);
            // Start a separate thread that does the actual work.
            if ((workerThread == null) ||
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() +
                    " - Starting the service worker thread.");
#endif
                workerThread = new Thread(new ThreadStart(ServiceWorkerMethod));
                workerThread.Start();
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() +
                    " - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
            myServiceStatus.currentState = (int)State.SERVICE_RUNNING;
            SetServiceStatus(handle, myServiceStatus);
        }
        // Stop this service.
        protected override void OnStop()
        {
            // New in .NET Framework version 2.0.
            this.RequestAdditionalTime(4000);
            // Signal the worker thread to exit.
            if ((workerThread != null) && (workerThread.IsAlive))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() +
                    " - Stopping the service worker thread.");
#endif
                pause.Reset();
                Thread.Sleep(5000);
                workerThread.Abort();
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() +
                    " - OnStop Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
            // Indicate a successful exit.
            this.ExitCode = 0;
        }
        // Pause the service.
        protected override void OnPause()
        {
            // Pause the worker thread.
            if ((workerThread != null) &&
                (workerThread.IsAlive) &&
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) == 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() +
                    " - Pausing the service worker thread.");
#endif
                pause.Reset();
                Thread.Sleep(5000);
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() +
                    " OnPause - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
        }
        // Continue a paused service.
        protected override void OnContinue()
        {
            // Signal the worker thread to continue.
            if ((workerThread != null) &&
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() +
                    " - Resuming the service worker thread.");
#endif
                pause.Set();
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() +
                    " OnContinue - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
        }
        // Handle a custom command.
        protected override void OnCustomCommand(int command)
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() +
                " - Custom command received: " +
                command.ToString());
#endif
            // If the custom command is recognized,
            // signal the worker thread appropriately.
            switch (command)
            {
                case (int)SimpleServiceCustomCommands.StopWorker:
                    // Signal the worker thread to terminate.
                    // For this custom command, the main service
                    // continues to run without a worker thread.
                    OnStop();
                    break;
                case (int)SimpleServiceCustomCommands.RestartWorker:
                    // Restart the worker thread if necessary.
                    OnStart(null);
                    break;
                case (int)SimpleServiceCustomCommands.CheckWorker:
#if LOGEVENTS
                    // Log the current worker thread state.
                    EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() +
                        " OnCustomCommand - Worker thread state = " +
                        workerThread.ThreadState.ToString());
#endif
                    break;
                default:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnCustomCommand",
                        DateTime.Now.ToLongTimeString());
#endif
                    break;
            }
        }
        // Handle a session change notice
        protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() +
                " - Session change notice received: " +
                changeDescription.Reason.ToString() + "  Session ID: " +
                changeDescription.SessionId.ToString());
#endif
            switch (changeDescription.Reason)
            {
                case SessionChangeReason.SessionLogon:
                    userCount += 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionLogon, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.SessionLogoff:
                    userCount -= 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionLogoff, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.RemoteConnect:
                    userCount += 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " RemoteConnect, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.RemoteDisconnect:
                    userCount -= 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " RemoteDisconnect, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.SessionLock:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionLock");
#endif
                    break;
                case SessionChangeReason.SessionUnlock:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange",
                        DateTime.Now.ToLongTimeString() +
                        " SessionUnlock");
#endif
                    break;
                default:
                    break;
            }
        }
        // Define a simple method that runs as the worker thread for
        // the service. 
        public void ServiceWorkerMethod()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                " - Starting the service worker thread.");
#endif
            try
            {
                do
                {
                    // Simulate 4 seconds of work.
                    Thread.Sleep(4000);
                    // Block if the service is paused or is shutting down.
                    pause.WaitOne();
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                        " - heartbeat cycle.");
#endif
                }
                while (true);
            }
            catch (ThreadAbortException)
            {
                // Another thread has signalled that this worker
                // thread must terminate.  Typically, this occurs when
                // the main service thread receives a service stop
                // command.
                // Write a trace line indicating that the worker thread
                // is exiting.  Notice that this simple thread does
                // not have any local objects or data to clean up.
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                    " - Thread abort signaled.");
#endif
            }
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                " - Exiting the service worker thread.");
#endif
        }
    }
}


// C++ language example
// Turn on the constant for trace output.
#define TRACE

#using <System.ServiceProcess.dll>
#using <System.dll>

using namespace System;
using namespace System::ComponentModel;
using namespace System::IO;
using namespace System::ServiceProcess;
using namespace System::Threading;
using namespace System::Diagnostics;

// Define custom commands for the SimpleService.
public enum class SimpleServiceCustomCommands
{
    StopWorker = 128,
    RestartWorker, CheckWorker
};


// Define a simple service implementation.
public ref class SimpleService: public System::ServiceProcess::ServiceBase
{
private:
    Thread^ workerThread;
    int userCount;
public:
    SimpleService()
    {
        CanPauseAndContinue = true;
        ServiceName = "SimpleService";
        workerThread = nullptr;
        CanHandleSessionChangeEvent = true;
    }

private:

    void InitializeComponent()
    {
        // Initialize the operating properties for the service.
        this->CanPauseAndContinue = true;
        this->CanShutdown = true;
        this->ServiceName = "SimpleService";
        this->CanHandleSessionChangeEvent = true;
    }

    // Start the service.
protected:
    virtual void OnStart( array<String^>^  ) override
    {
        // Start a separate thread that does the actual work.
        if ( (workerThread == nullptr) || ((workerThread->ThreadState & (System::Threading::ThreadState::Unstarted | System::Threading::ThreadState::Stopped)) != (System::Threading::ThreadState)0) )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Starting the service worker thread.", "OnStart" );
            workerThread = gcnew Thread( gcnew ThreadStart( this,&SimpleService::ServiceWorkerMethod ) );
            workerThread->Start();
        }

        if ( workerThread != nullptr )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnStart" );
        }
    }

    // Stop this service.
protected:
    virtual void OnStop() override
    {
        // Signal the worker thread to exit.
        if ( (workerThread != nullptr) && (workerThread->IsAlive) )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Stopping the service worker thread.", "OnStop" );
            workerThread->Abort();

            // Wait up to 500 milliseconds for the thread to terminate.
            workerThread->Join( 500 );
        }

        if ( workerThread != nullptr )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnStop" );
        }
    }

    // Pause the service.
protected:
    virtual void OnPause() override
    {
        // Pause the worker thread.
        if ( (workerThread != nullptr) && (workerThread->IsAlive) && ((workerThread->ThreadState & (System::Threading::ThreadState::Suspended | System::Threading::ThreadState::SuspendRequested)) == (System::Threading::ThreadState)0) )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Suspending the service worker thread.", "OnPause" );
            workerThread->Suspend();
        }

        if ( workerThread != nullptr )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnPause" );
        }
    }

    // Continue a paused service.
protected:
    virtual void OnContinue() override
    {
        // Signal the worker thread to continue.
        if ( (workerThread != nullptr) && ((workerThread->ThreadState & (System::Threading::ThreadState::Suspended | System::Threading::ThreadState::SuspendRequested)) != (System::Threading::ThreadState)0) )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Resuming the service worker thread.", "OnContinue" );
            workerThread->Resume();
        }

        if ( workerThread != nullptr )
        {
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnContinue" );
        }
    }

    // Handle a custom command.
protected:
    virtual void OnCustomCommand( int command ) override
    {
        Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Custom command received: " + command, "OnCustomCommand" );

        // If the custom command is recognized,
        // signal the worker thread appropriately.
        switch ( command )
        {
        case (int)SimpleServiceCustomCommands::StopWorker:

            // Signal the worker thread to terminate.
            // For this custom command, the main service
            // continues to run without a worker thread.
            OnStop();
            break;

        case (int)SimpleServiceCustomCommands::RestartWorker:

            // Restart the worker thread if necessary.
            OnStart( nullptr );
            break;

        case (int)SimpleServiceCustomCommands::CheckWorker:

            // Log the current worker thread state.
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Worker thread state = " + workerThread->ThreadState.ToString(), "OnCustomCommand" );
            break;

        default:
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Unrecognized custom command ignored!", "OnCustomCommand" );
            break;
        }
    }
protected:
    virtual void OnSessionChange(SessionChangeDescription changeDescription) override
    {
        Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Change description received: "
            + changeDescription.ToString(), "OnSessionChange" );

        switch (changeDescription.Reason)
        {
        case SessionChangeReason::SessionLogon:
            userCount += 1;
            Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " SessionLogon, total users: " +
                userCount.ToString(), "OnSessionChange" );
            break;
        case SessionChangeReason::SessionLogoff:
            userCount -= 1;
            Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " SessionLogoff, total users: " +
                userCount.ToString(), "OnSessionChange" );
            break;
        case SessionChangeReason::RemoteConnect:
            userCount += 1;
            Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " RemoteConnect, total users: " +
                userCount.ToString(), "OnSessionChange" );
            break;
        case SessionChangeReason::RemoteDisconnect:
            userCount -= 1;
            Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " RemoteDisconnect, total users: " +
                userCount.ToString(), "OnSessionChange" );
            break;
        case SessionChangeReason::SessionLock:
            Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " SessionLock", "OnSessionChange" );
            break;
        case SessionChangeReason::SessionUnlock:
Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " SessionUnlock", "OnSessionChange" );
            break;

        default:
            Trace::WriteLine( DateTime::Now.ToLongTimeString() +
                " - Unhandled session change event.", "OnSessionChange" );
            break;
        }
    }
    // Define a simple method that runs as the worker thread for
    // the service. 
public:
    void ServiceWorkerMethod()
    {
        Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Starting the service worker thread.", "Worker" );
        try
        {
            for ( ; ;  )
            {

                // Wake up every 10 seconds and write
                // a message to the trace output.
                Thread::Sleep( 10000 );
                Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - heartbeat cycle.", "Worker" );
            }
        }
        catch ( ThreadAbortException^ )
        {
            // Another thread has signalled that this worker
            // thread must terminate.  Typically, this occurs when
            // the main service thread receives a service stop
            // command.
            // Write a trace line indicating that the worker thread
            // is exiting.  Notice that this simple thread does
            // not have any local objects or data to clean up.
            Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Thread abort signaled.", "Worker" );
        }

        Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Exiting the service worker thread.", "Worker" );
    }
};

int main()
{
    String^ logFile = "C:\\service_log.txt";
    TextWriterTraceListener^ serviceTraceListener = nullptr;

    // Create a log file for trace output.
    // A new file is created each time.  If a
    // previous log file exists, it is overwritten.
    StreamWriter^ myFile = File::CreateText( logFile );

    // Create a new trace listener that writes to the text file,
    // and add it to the collection of trace listeners.
    serviceTraceListener = gcnew TextWriterTraceListener( myFile );
    Trace::Listeners->Add( serviceTraceListener );
    Trace::AutoFlush = true;
    Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Service main method starting...", "Main" );

    // Load the service into memory.
    System::ServiceProcess::ServiceBase::Run( gcnew SimpleService );
    Trace::WriteLine( DateTime::Now.ToLongTimeString() + " - Service main method exiting...", "Main" );

    // Remove and close the trace listener for this service.
    Trace::Listeners->Remove( serviceTraceListener );
    serviceTraceListener->Close();
    serviceTraceListener = nullptr;
    myFile->Close();
}

상속 계층 구조

System.Object
   System.MarshalByRefObject
     System.ComponentModel.Component
      System.ServiceProcess.ServiceBase
스레드로부터의 안전성

이 형식의 모든 public static(Visual Basic의 경우 Shared) 멤버는 스레드로부터 안전합니다. 인터페이스 멤버는 스레드로부터 안전하지 않습니다.

플랫폼

Windows 98, Windows 2000 SP4, Windows Server 2003, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP SP2, Windows XP Starter Edition

.NET Framework에서 모든 플래폼의 모든 버전을 지원하지는 않습니다. 지원되는 버전의 목록은 시스템 요구 사항을 참조하십시오.

버전 정보

.NET Framework

2.0, 1.1, 1.0에서 지원

참고항목

Servicebase 멤버
System.ServiceProcess 네임스페이스
ServiceProcessInstaller
ServiceInstaller



출처 : http://msdn.microsoft.com/ko-kr/library/system.serviceprocess.servicebase(v=VS.80).aspx
Posted by SB패밀리