지금껏 이벤트로그에 쓰는건 해봤어도, 이벤트 로그를 읽을일이 없어 그냥 무심히 지나쳐왔었는데요..
일이란걸 하다보니, 이벤트 로그를 읽어들이면 간단하게 끝날 수 있는데,
직접 코딩하려니 무자게 빡센 업무가 되는것들도 있더라구요.. 흠...

지금 하려는 작업은 시스템 이벤트중 보안(Security) 이벤트에 먼가가 써지면 그 이벤트를 바로 받아서
어떤게 써졌는지 읽어오는 작업이 되겠습니다.

// 이벤트 로그의 핸들과, 그것의 이벤트를 처리할 EVENT 핸들
HANDLE m_hEventLog;
HANDLE m_hEvent;

// 이벤트 로그를 오픈하고, 새로운 이벤트를 하나 만든다.
m_hEventLog = OpenEventLog(NULL, "Security);
m_hEvent = CreateEvent(NULL, FALSE, FALSE, "crowback_m_hEvent");

// 열린 이벤트로그에, 새로 만든 EVENT를 등록하여
// 이벤트 로그의 이벤트를 받아보자.
if(NotifyChangeEventLog(m_hEventLog, m_hEvent) == FALSE)
{
   if(m_hEvent)
        CloseHandle(m_hEvent);
   CloseEventLog(m_hEventLog);
}

비동기로 계속 이벤트를 모니터링 해야하므로 별도의 스레드가 하나 있어야겠죠?
프로그램 자체의 메인 루프에다가 처리해도 상관없을꺼구요..

// 스레드나 메인루프에서 이벤트를 대기하다가, 시그널이 날라오면
// 해당 이벤트 로그를 열어서 필요한 정보를 추출한다.
while(종료조건)
{
    if(WaitForSingleObject(pThis->EventLogGetEventHandle(), 100) == WAIT_OBJECT_0)
        EventLogCallback();
}

// 이벤트 로그를 열어서 최근 데이터를 읽어들인다.
void EventLogCallback()
{
    HANDLE evt = OpenEventLog(NULL, "Security");
    if (evt == NULL)
        return;

    BYTE bBuffer[4096] = {0};
    DWORD dwRead, dwNeeded;
    EVENTLOGRECORD *pevlr = (EVENTLOGRECORD *) &bBuffer;
    LPCTSTR lpSourceName;
    
    if(ReadEventLog(evt,   // Event log handle
        EVENTLOG_BACKWARDS_READ | // 최근 것을 읽어들인다.
        EVENTLOG_SEQUENTIAL_READ, // Sequential read
        0,       // Ignored for sequential read
        pevlr,      // Pointer to buffer
        4096,      // Size of buffer
        &dwRead,     // Number of bytes read
        &dwNeeded) == FALSE)   
    {
        CloseEventLog(evt);
        return;
    }
    CloseEventLog(evt);

    lpSourceName = (LPCTSTR) ((LPBYTE) pevlr + sizeof(EVENTLOGRECORD));

    // EVENTLOGRECORD 구조체에 필요한 정보가 모두 들어있다.
}


기존에 서비스 프로그램을 다루면서, 프로그램적으로 서비스를 멈추는 것은
단순하게 ControlService(핸들, SERVICE_CONTROL_STOP, 개체포인터);
이런식으로 처리가 가능하다.

그런데? 중지 시키려고 하는 서비스의 종속된 서비스가 존재한다면?
그냥 중지 시키면 ERROR_DEPENDENT_SERVICES_RUNNING 메시지를 받게된다.
즉, 종속된 서비스가 존재하기 때문에 해당 서비스를 중지 할 수 없다.

그럴 경우 EnumDependentServices API를 이용하여, 종속 서비스 목록을 얻어와서
해당 서비스를 하나 하나 전부 종료 시켜주어야 한다.


아.. 참으로 오랜만에 공개글을 올리게 되네요..
한동안 회사일로 바쁘다 보니, 비공개 자료만 쌓아왔는데.. ^^;

MSDN 에서 보면 GetVersionEx() 함수를 이용하여, 윈도우의 각종 버전 및 플래폼
그리고, 서비스팩 정보를 이용할 수 있는 샘플 자료가 있습니다.

위 자료를 좀 개선해서, Windows 2008 Servers 및 Windows Vista 에서도 정상적으로 동작하는
모델을 만들어 봤습니다. 클래스의 이름은 CWindowsVersion 입니다.

또한, 기존에 32 비트시스템에서 제작되어진 어플리케이션이 64 비트 윈도우에서 구동될 때
호환모드로 구동하게 되는데, 별다른 문제는 없지만 레지스트리를 액세스할 때 다음과 같은
문제가 발생합니다.

32비트 호환모드로 구동되는 프로그램은 HKEY_LOCAL_MACHINE\SOFTWARE 경로를
직접 액세스 할 수 없습니다.

64비트 전용으로 생성된 소프트웨어는 문제가 없지만 32비트로 만들어져 호환모드로 동작할 경우는
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node 아래처럼 32비트 응용프로그램을 위한
전용 경로를 사용해야합니다.

이것을 일일이 하나씩 변경하기 힘들어서, 64비트 운영체제에서 테스트해야하는 프로그램중에
32트로 만들어져 있고, 위의 경로및 그 경로의 하위를 액세스하는 경우 자동으로 경로를 변경해주어
동작하는데 문제가 없도록 API를 만들어 봤습니다.

소스는 Visual C++ 6.0, SP6, Enterprize Edition, 영문버전에서 작성되었으며
테스트는 Windows XP 32/64, Windows Server 2003 32/64, Windows Vista 32/64, Windows Server 2008 64
에서 테스트를 마쳤습니다.




C나 C++에서 수식을 연산하다 잘못된 메모리를 읽거나, 저장된 파일을 읽어들이거나
0으로 나누거나 등등의 이유로 실수값에 -1.#INF0 과 같은 값이 지정된 것을 본적이
있을것이다. 혹은 -1.#IND0 과 같은 것도 있다.

.#IND Not a Number <= 숫자가 아닌값(실수체계에서 나올 수 없는 값과 같은 경우)
.#INF Infinite Number <= 0으로 나누는 등으로 인하여 무한히 큰값

숫자가 아닌값을 검출할 때는 CRT의 _isnan()
무한대의 숫자를 검출할 때는 CRT의 _finite()
주어진 숫자가 의심스러울 때 혹은 상태를 검출할 때는 _fpclass()
모두 float.h 에 선언되어 있습니다.

제목에서 처럼 0으로 나누어졌을 때는 숫자가 무한히 커져 .#INF00 의 무한값을 나타내고
다른 예로 double a = sqrt(-1) (데브피아 Neo.L 님께서 제시해주신 예시) 과 같은 경우는
실수체계에서 표현할 수 없는 숫자라는 의미로 .#IND00 과 같이 표기됩니다.

이 부분은  IEEE754,854 문서에 표기된 표준 표기에 의한것 (데브피아 stiletto 님께서 표기해줌)
으로 모두 정상적인 표기 방법입니다.

다행한것이 설계를 그렇게 한것인지, 저런 값이 나온다고 하여 연산하다가 죽는 경우는 없다는
점이다. 단, 필요한 요소에서 꼭 확인하여 엉뚱한 결과로 인한 피해를 줄이자.

사용자 삽입 이미지

















잘 모르는 내용을 올리다가 망신살도 좀 뻗치고.. 아무튼 이런 기회에 새로운걸 공부해 보네요.
서비스 프로그램을 작성하다 보면..
간혹 데스크탑과 연동해야 하는 일이 발생한다.

입력없는 콘솔 프로그램 같은 경우는 그냥 서비스에서 바로 수행하면 되지만
입력을 받는 콘솔이나, GUI를 가진 프로그램을 띄워야할 경우는
프로세스 목록에만 나오고.. 깜깜 무소식이다.

일반 응용프로그램에서야 WTSRegisterSessionNotification 함수를 이용하여 아주 쉽게
로그온된 시점을 구할 수 있지만 불행하게도 서비스에서는 사용할 수 없다.


또한 서비스 시작시에 응용 프로그램을 수행시키면, 아직 로그온 되기 전이기때문에
저런 설정을 다 해놓는다 하여도 로그온된 화면에는 아무것도 보이지 않을 수 있다.

1. 꼭 서비스로 관리해야하는가?
2. 입력을 가지는 콘솔이나 GUI를 가졌는가?
3. 서비스 구동시에 시작해야 하는가?
4. 로그온 된 데스크탑에 보여주어야 하는가?

위 사항들을 잘 판단하고 그래도 꼭 필요하다면 다음과 같은 정보를 구해야한다.
1. 서비스로 개발하기
2. 데스크탑과 연동하는 옵션
3. 로그온된 시점 구하기

1. 서비스로 개발하기
위 사항은 이미 자료가 많이 나와있고, 대부분 알려진 자료이므로 그냥 좋은 자료를 찾는다 ^^;

2. 데스크탑과 연동하는 옵션
       첫번째로 가장 쉬운 방법은 서비스 관리자를 이용하는 방법이다.

사용자 삽입 이미지

     그림에서 보이는것 처럼 로그온 설정시에 서비스와 데스크탑 상호 작용 허용에 첵크를
     해줌으로써 아주 간단하게 해결할 수 있다.

     두번째는 서비스를 인스톨할 때, 즉 CreateService 함수를 이용하여 서비스를 설치할 때
     다섯번째 인자에 SERVICE_INTERACTIVE_PROCESS 를 함께 넣어주는 것이다.
     이것은 첫번째 방법을 프로그램적으로 해결하는 것이다.

3. 로그온된 시점 구하기
로그온된 시점을 구하는 방법도 그리 어렵지 않다. 하지만 제약사항이 많아서..
특히나 지금 처리하는 방법은 Windows XP 이상, Windows Server 2003 이상에서만
동작하는 방법이므로, 하위 버전 윈도우를 처리하는 경우에는 해당사항이 없다. -_-;;;
(예전에는 이벤트 로그를 뒤적거려서 처리했었다...)

서비스를 핸들하기 위하여 RegisterServiceCtrlHandler 함수 대신에 좀더 구체적인 정보를
전달해주는 RegisterServiceCtrlHandlerEx 를 이용하는 방법이다.

RegisterServiceCtrlHandlerEx API는 시스템의 세션정보 변화를 감지하는 이벤트인
WM_WTSSESSION_CHANGE 를 처리할 수 있도록 해준다.

SetServiceStatus 에서 SERVICE_STATUS 값의 dwControlsAccepted 값에 꼭
SERVICE_ACCEPT_SESSIONCHANGE 를 함께 넣어주도록 하자.

이렇게 RegisterServiceCtrlHandlerEx 에 전달된 콜백함수에는 다음과 같은 인자가 있다.
DWORD WINAPI HandlerEx(
  [in]                 DWORD dwControl,
  [in]                 DWORD dwEventType,
  [in]                 LPVOID lpEventData,
  [in]                 LPVOID lpContext
);

저기서 첫번째 인자에 SERVICE_CONTROL_SESSIONCHANGE 가 넘어오면 로그온 세션에
무언가 변화가 생긴것이다.

두번째 인자로 어떤 변화가 발생하였는지를 감지할 수 있다. MSDN의 설명을 참고해보면...
Value Meaning

WTS_CONSOLE_CONNECT
0x1

A session was connected to the console terminal.

WTS_CONSOLE_DISCONNECT
0x2

A session was disconnected from the console terminal.

WTS_REMOTE_CONNECT
0x3

A session was connected to the remote terminal.

WTS_REMOTE_DISCONNECT
0x4

A session was disconnected from the remote terminal.

WTS_SESSION_LOGON
0x5

A user has logged on to the session.

WTS_SESSION_LOGOFF
0x6

A user has logged off the session.

WTS_SESSION_LOCK
0x7

A session has been locked.

WTS_SESSION_UNLOCK
0x8

A session has been unlocked.

WTS_SESSION_REMOTE_CONTROL
0x9

A session has changed its remote controlled status. To determine the status, call GetSystemMetrics and check the SM_REMOTECONTROL metric.


그러므로 위시점에서 WTS_SESSION_LOGON 일 경우에 프로그램을 기동시키면 정확하게
로그온된 시점에 프로그램이 구동하게 된다.

서비스 프로그램을 작성하다 보면, 디버깅을 할 때 현재 어플리케이션으로
구동중인지 서비스로 구동중인지를 내부적으로 구분할 수 있어야한다.
(여러가지 방법이 있겠지만, 아는게 없어서 ㅜㅜ)

이를 쉽게 해결하는 방법은 다음과 같다.

메인 쯔음해서 GetConsoleWindow() 함수를 호출한 결과를 가지고 여부를
자동으로 구분할 수 있다.

응용 프로그램 모드로 구동하게 되면 위 함수가 HWND 타입의 핸들을 리턴하게 된다.
하지만 시스템 서비스 모드로 구동중이라면 NULL을 리턴한다.

즉, 프로그램 main에서 저 핸들값을 이용하여 StartServiceCtrlDispatcher 를 호출할 것인지
디버그용 메인을 호출할 것인지를 결정할 수 있는 것이다.

곁들여서 GetUserName() 를 이용하여 현재 어떤 계정으로 구동하는지도
첨부하면 금상첨화겠죠?

http://www.kriss.re.kr/ 한국 표준과학 연구원

SNTP (Simple Network Time Protocol)를 이용하며, 한국표준시 Time Server에 자동으로 접속하여 시간을 맞출 수 있다. (타임서버의 도메인: time.kriss.re.kr)


참고 소스는 http://www.codeproject.com/KB/IP/csntp.aspx
CSNTPClient - An SNTP Implementation

참고 자료는 http://blog.naver.com/cyonsang?Redirect=Log&logNo=140015175394
SNTP(단일 네트워크 기간 프로토콜) 시간 서버 목록


위와 같은 자료가 필요한 이유는, 배포된 프로그램에 시간을 이용해서 확인하는 작업등이
존재할경우 CMOS나, OS시간을 변경시켜버리면 확인하기 힘든 부분이 존재하기 때문이다.
여러가지 방식으로 막을 수는 있겠지만, 인터넷에 연결되어져야 하는 컴퓨터라면 혹은
인터넷이 되어야만 사용할 수 있는 프로그램이라면 위 방법으로 쉽게 해결할 수 있다.
프로그램을 작성하다 보니.. 파일의 시간을 변경할 일이 발생했다...
Win32 API에서 여러가지 함수를 제공하기는 하는데.. time_t를 바로 지원하지는 않는다. -_-;;;

다행히도 MSDN에서 이를 지원하는 KB가 있어 옮겨 보았다.

How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME

Article ID : 167296
Last Review : November 21, 2006
Revision : 3.3
This article was previously published under Q167296

SUMMARY

Under UNIX platforms, file times are maintained in the form of a ANSI C runtime arithmetic type named 'time_t', which represents seconds since midnight January 1, 1970 UTC (coordinated universal time).

Under Win32 platforms, file times are maintained primarily in the form of a 64-bit FILETIME structure, which represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time).

This article shows how to convert UNIX time to other Win32 time formats.

MORE INFORMATION

The following function converts a filetime in the UNIX time_t format to a Win32 FILETIME format. Note that time_t is a 32-bit value and FILETIME is a 64-bit structure, so the Win32 function, Int32x32To64() is used in the following function:
   #include <winbase.h>
   #include <winnt.h>
   #include <time.h>

   void UnixTimeToFileTime(time_t t, LPFILETIME pft)
   {
     // Note that LONGLONG is a 64-bit value
     LONGLONG ll;

     ll = Int32x32To64(t, 10000000) + 116444736000000000;
     pft->dwLowDateTime = (DWORD)ll;
     pft->dwHighDateTime = ll >> 32;
   }
				
Once the UNIX time is converted to a FILETIME structure, other Win32 time formats can be easily obtained by using Win32 functions such as FileTimeToSystemTime() and FileTimeToDosDateTime().
   void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
   {
     FILETIME ft;

     UnixTimeToFileTime(t, &ft);
     FileTimeToSystemTime(&ft, pst);
   }
				

APPLIES TO
Microsoft Win32 Application Programming Interface, when used with:
    Microsoft Windows 95
    Microsoft Windows 98 Standard Edition
    Microsoft Windows Millennium Edition
    Microsoft Windows NT 3.51 Service Pack 5
    Microsoft Windows NT 4.0
    Microsoft Windows 2000 Standard Edition
    Microsoft Windows XP Professional

Back to the top

Keywords:
kbdatetime kbhowto kbkernbase kbprogramming KB167296
 

권한에 관한 부분은 상당히 방대한 양이라.. 그냥 필요해서 쓰는것만 추려봤습니다.
MSDN에 잘 나와았지만 대부분 WCHAR 타입의 인자를 넘겨야해서 그냥 껍데기를
씌운 형태입니다. ^^;

1. 유저 영역
   -> 유저 생성, 유저 삭제, 유저 목록, 암호 변경, 유저가 속한 그룹 목록, 유저 정보등..

2. 그룹 영역
  -> 그룹 생성, 그룹 삭제, 그룹 목록, 그룹에 유저 추가, 그룹에서 유저 삭제등..

3. 권한 영역
  -> 유저의 SID 얻어오기, SID를 문자열로 만들기, 현재 유저의 권한 얻어오기
      권한의 활성화/비활성화, 프로세스에 속한 권한 목록 얻어오기, 권한 상승
      프로세스 소유자 얻어오기 등등...


// Policy.h: interface for the CPolicy class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_POLICY_H__8DE86AF1_C525_4546_A661_0FC4D12902EF__INCLUDED_)
#define AFX_POLICY_H__8DE86AF1_C525_4546_A661_0FC4D12902EF__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

#include <ntsecapi.h>
#include <vector>
#include <comutil.h>
#include <lm.h>
#include <sddl.h>
#include <Ntsecapi.h>


namespace CLM // Control Local Machine
{
    LPCTSTR GetLogonUser();
    LPCTSTR GetHostName();
    LPCTSTR GetDomainName();

    LPWCH  MBtoWC(LPCTSTR src, PWCHAR dst, int dstlen);
    LPTSTR WCtoMB(LPCWCH src, LPTSTR dst, int dstlen);

    void InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String);

    NTSTATUS OpenPolicy(
        LPCTSTR ServerName,                // machine to open policy
        DWORD DesiredAccess,            // desired access to policy
        PLSA_HANDLE PolicyHandle);        // resultant policy handle, must be LsaClose(PolicyHandle)

    NTSTATUS OpenPolicy(
        PLSA_HANDLE PolicyHandle);        // resultant policy handle, must be LsaClose(PolicyHandle)

    BOOL GetUserSid(
        LPCTSTR servername,                // where to lookup account
        LPCTSTR username,                // account of interest
        PSID *Sid);                        // resultant buffer containing SID, must be HeapFree(GetProcessHeap(), 0, pSid);

    BOOL GetCurrentUserSid(
        PSID *pSid);                    // resultant buffer containing SID, must be HeapFree(GetProcessHeap(), 0, pSid);

    BOOL GetSIDToString(PSID sid, LPTSTR& strstring);

    namespace USER
    {
        /*  Declared in Lmaccess.h; include Lm.h. Use Netapi32.lib.

            NetUserAdd                Adds a user account and assigns a password and privilege level. 
            NetUserChangePassword    Changes a user's password for a specified network server or domain. 
            NetUserDel                Deletes a user account from the server. 
            NetUserEnum                Lists all user accounts on a server. 
            NetUserGetGroups        Returns a list of global group names to which a user belongs. 
            NetUserGetInfo            Returns information about a particular user account on a server. 
            NetUserGetLocalGroups    Returns a list of local group names to which a user belongs. 
            NetUserSetGroups        Sets global group memberships for a specified user account. 
            NetUserSetInfo            Sets the password and other elements of a user account. 
        */

        NET_API_STATUS NetUserAdd(
            LPCTSTR servername,                // NULL is localcomputer
            LPCTSTR username,                // Not NULL
            LPCTSTR password,                // allow NULL
            LPCTSTR comment,                // allow NULL
            DWORD privilege,                // USER_PRIV_GUEST, USER_PRIV_USER, USER_PRIV_ADMIN
            DWORD flags);                    // 권한에 대한 제한. UF_SCRIPT | UF_DONT_EXPIRE_PASSWD 기타 등등..

        NET_API_STATUS NetUserChangePassword(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR username,                // NULL is current logon user
            LPCTSTR oldpassword,            // current password, Not NULL
            LPCTSTR newpassword);            // new password, Not NULL
    
        NET_API_STATUS NetUserDel(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR username);                // Not NULL
    
        NET_API_STATUS NetUserEnum(
            LPCTSTR domainname,                // NULL is localcomputer
            LPDWORD dwCount,                // user count
            LPUSER_INFO_20& userinfos);        // user info array, must be free -> NetApiBufferFree(userinfos);
    
        NET_API_STATUS NetUserGetGroups(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR username,                // NULL is current user
            std::vector<_bstr_t>& parray);    // global group name array

        NET_API_STATUS NetUserGetInfo(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR username,                // NULL is current user
            LPUSER_INFO_20& userinfos);        // user info array, must be free -> NetApiBufferFree(userinfos);
    
        NET_API_STATUS NetUserGetLocalGroups(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR username,                // NULL is current user
            std::vector<_bstr_t>& parray);    // local group name array
    
        NET_API_STATUS NetUserSetGroups(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR username,                // NULL is current user
            LPCTSTR groupname);                // Not NULL, global groupname
    }


    namespace GROUP
    {
        /*  Declared in Lmaccess.h; include Lm.h. Use Netapi32.lib.

            NetLocalGroupAdd        Creates a local group. 
            NetLocalGroupAddMembers Adds one or more users or global groups to an existing local group. 
            NetLocalGroupDel        Deletes a local group, removing all existing members from the group. 
            NetLocalGroupDelMembers Removes one or more members from an existing local group. 
            NetLocalGroupEnum        Returns information about each local group account on a server. 
            NetLocalGroupGetInfo    Returns information about a particular local group account on a server. 
            NetLocalGroupGetMembers Lists all members of a specified local group. 
            NetLocalGroupSetInfo    Sets general information about a local group. 
            NetLocalGroupSetMembers Assigns members to a local group. 
        */
    
        NET_API_STATUS NetLocalGroupAdd(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR groupname,                // Not NULL, groupname
            LPCTSTR comment);                // Allow NULL

        NET_API_STATUS NetLocalGroupAddMembers(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR groupname,                // Not NULL, groupname
            LPCTSTR username);                // Not NULL, username

        NET_API_STATUS NetLocalGroupDel(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR groupname);                // Not NULL, groupname
    
        NET_API_STATUS NetLocalGroupDelMembers(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR groupname,                // Not NULL, groupname
            LPCTSTR username);                // Not NULL, username

        NET_API_STATUS NetLocalGroupEnum(
            LPCTSTR domainname,                // NULL is localcomputer
            LPDWORD dwCount,                // group count
            PLOCALGROUP_INFO_1& groupinfo);    // group info array, must be free -> NetApiBufferFree(groupinfo);

        NET_API_STATUS NetLocalGroupGetInfo(
            LPCTSTR domainname,                // NULL is localcomputer
            LPCTSTR groupname,                // Not NULL, groupname
            PLOCALGROUP_INFO_1& groupinfo);    // group info, must be free -> NetApiBufferFree(groupinfo);

    };

    
    
    namespace PRIVILEGE
    {
        // 현재 프로세스에 주어진 권한을 인에이블/디스에이블 시킨다.
        BOOL SetProcessPrivilege(
            LPCTSTR lpszPrivilege,            // privilege to grant
            BOOL bEnablePrivilege);            // add or remove

        // 사용자 계정에 특별한 권한을 추가시킨다.
        NTSTATUS SetPrivilegeOnAccount(
            LSA_HANDLE PolicyHandle,        // open policy handle
            PSID AccountSid,                // SID to grant privilege to
            LPWSTR PrivilegeName,            // privilege to grant (Unicode)
            BOOL bEnable);                    // enable or disable

        // 해당 유저에게 할당된 부가적인 프리빌리지를 얻어온다.
        // 일반적인 프리빌리지를 얻어올 경우는, 해당 유저가 띄운 프로세스를 이용하여
        // 아래의 GetPrivilegeFromProcessHandle 함수를 이용하여 가져온다.
        NTSTATUS EnumPrivilegeOnAccount(
            LSA_HANDLE PolicyHandle,        // open policy handle
            PSID AccountSid,                // SID to grant privilege to
            std::vector<_bstr_t>& parray);    // privileges array

        // 프로세스 핸들을 이용하여 해당 유저 이름을 얻어온다.
        BOOL GetUserFromProcessHandle(
            LPTSTR AccountName,                // account of interest
            DWORD* cbName,                    // string buffer length
            HANDLE hProcess = NULL);        // process id, NULL is owner process

        // 프로세스 아이디를 이용하여 해당 유저 이름을 얻어온다.
        BOOL GetUserFromProcessID(
            LPTSTR AccountName,                // account of interest
            DWORD* cbName,                    // string buffer length
            DWORD nProcessID = 0xFFFFFFFF);    // process id, 0xFFFFFFFF is owner process

        // 프로세스 핸들을 이용하여 해당 프로세스에 설정된 프리빌리지 목록을 얻어온다.
        BOOL GetPrivilegeFromProcessHandle(
            std::vector<_bstr_t>& parray,    // privileges array
            HANDLE hProcess = NULL);        // process id, NULL is owner process

        // 프로세스 아이디을 이용하여 해당 프로세스에 설정된 프리빌리지 목록을 얻어온다.
        BOOL GetPrivilegeFromProcessID(
            std::vector<_bstr_t>& parray,    // privileges array
            DWORD nProcessID = 0xFFFFFFFF);    // process id, 0xFFFFFFFF is owner process
    };
};

#endif
// !defined(AFX_POLICY_H__8DE86AF1_C525_4546_A661_0FC4D12902EF__INCLUDED_)







작업을 하다보니 4GB 크기가 넘는 파일을 다루어야 할 일이 생겼네요.
윈도우즈 커널에 _hread, _hwrite 등의 숨겨진 API가 제공되지만..
이런거 찾아다가 처리하기가 여간 귀찬아서.. ㅎㅎ;

대형 파일을 그냥 fopen, open, OpenFile 등등.. 어떤 API로 처리하든지
그냥 읽고 쓰기는 가능합니다.
(단, 이 방법을 사용하시더라도 fseek, lseek는 불가능합니다.
 파일을 seek해야 할 경우는 처음에 이야기 처럼 kernel에 숨겨진 위의 함수들을
 찾아서 사용하시던지, Visual Studio 2005 이상 버전을 사용하세요.

http://support.microsoft.com/kb/q100513/
위의 주소는 MS의 KB로 Visual Basic에서 대형파일을 어떻게 처리하는지에
대한 내용입니다. 내용을 보시고 VC로 포팅하는건 ~~
)



단지, 크기를 읽을 때 문제가 발생하죠..
Visual Studio 2005 이상 버전에서는 64비트 크기를 지원하는 새로운
API들이 제공되니 그냥 그걸 쓰시면 되고...

저는 몇몇 가지를 빼곤 대부분 Visual Studio 6.0을 사용하는 관계로, 6.0을 사용하시는
분들에게만 해당되는 내용이 될것입니다.

아래는 데브피아에 올라온 원문입니다.

 4.2기가 바이트 이상의 파일을 읽고 싶습니다. [답을 찾았습니다.]  | VC++ 일반 2007-04-09 오전 11:07:43
김태권 (jukyou)  김태권님께 메시지 보내기김태권님을 내 주소록에 추가합니다.김태권님의 개인게시판 가기 번호: 650715   / 평점:  (9.0)  / 읽음:80

안녕하십니까? 이전에 제 우매한 질문에 여러분께서 답변을 해주셔셔 감사드린다는 말씀 전해 드립니다.


저번 주 주말에 답을 찾아서 답을 올립니다.


강태호 (cartarsis) 님께서 답변 주신 내용과 MSDN을 읽어 보고 해결하였습니다.

우선 4.2기가 바이트 이상의 파일을 읽어야하는 상황이 있으신 분들을 위해 글을 남겨 놓습니다.



소스는 아래와 같습니다.


HANDLE hFile;

unsigned long nSizeHigh = 0;

unsigned long nSizeLow = 0;

__int64 nSize = 0;

hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

nSizeLow = GetFileSize(hFile, &nSizeHigh);

nSize = nSizeHigh;

nSize <<= 32;

nSize |= nSizeLow;

TRACE("Size : %I64d\n", nSize);


좋은 하루 되세요~~


그럼 이만 줄입니다.

+ Recent posts