네트워크 정보 얻어오는 방법
2001/10/26 조경민 bro@shinbiro.com
====================================================================
1. MAC Address 그냥 보는 방법
C:\>arp -a

Interface: 211.174.252.118 on Interface 0x1000003
  Internet Address      Physical Address      Type
  211.174.252.1         00-90-27-2b-ec-80     dynamic
  211.174.252.54        00-c0-26-a1-2a-9a     dynamic


2. GetNetworkParams를 쓰면 네트워크 정보를 얻어올 수 있다.
게이트웨이 Wins , proxy사용여부 등등 설정 값 얻어올수있음.
(98 이상 플랫폼SDK필요)

GetAdaptersInfo를 쓰면 MAC어드레드 등을 얻어올수있음

DWORD GetAdaptersInfo(
  PIP_ADAPTER_INFO pAdapterInfo,  // buffer to receive data
  PULONG pOutBufLen               // size of data returned
);

pAdapterInfo안에
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]
Specifies the hardware address for the adapter.
가 MAC 어드레스로  6자리의 바이트의 하나씩 주소다
00.00.00.00.00.00

--------------------------------------------------

IP_INTERFACE_INFO ifTable;

if ( GetInterfaceInfo(&ifTable, sizeof(ifTable)) != NO_ERROR )
{
    OutputDebugString("Fail..\r\n");
    return FALSE;
}

CString strDebug;

strDebug.Format("NumAdapters Number : %d\r\n", ifTable.NumAdapters);
OutputDebugString(strDebug);

for ( INT i=0 ; i<ifTable.NumAdapters ; i++ )
{
    strDebug.Format("[%d] %s\r\n", Adapter[i].Index, Adapter[i].Name);
}

--------------------------------------------------
3. NIC 카드 랜카드 이름 얻기
source code from 진호
void CNetworkDlg::OnIphlpapiButton()
{
    DWORD Err;

    PFIXED_INFO pFixedInfo;
    DWORD FixedInfoSize = 0;

    PIP_ADAPTER_INFO pAdapterInfo, pAdapt;
    DWORD AdapterInfoSize;
    PIP_ADDR_STRING pAddrStr;
        CString strResult,strTemp;

    //
    // Get the main IP configuration information for this machine using a FIXED_INFO structure
    //
    if ((Err = GetNetworkParams(NULL, &FixedInfoSize)) != 0)
    {
        if (Err != ERROR_BUFFER_OVERFLOW)
        {
            AfxMessageBox("GetNetworkParams sizing failed with error\n");
            return;
        }
    }

    // Allocate memory from sizing information
    if ((pFixedInfo = (PFIXED_INFO) GlobalAlloc(GPTR, FixedInfoSize)) == NULL)
    {
        AfxMessageBox("Memory allocation error\n");
        return;
    }

    if ((Err = GetNetworkParams(pFixedInfo, &FixedInfoSize)) == 0)
    {
                strTemp.Format("\tHost Name . . . . . . . . . : \t%s\n", pFixedInfo->HostName);
                strResult=strTemp;
        strTemp.Format("\tDNS Servers . . . . . . . . : \t%s\n", pFixedInfo->DnsServerList.IpAddress.String);
                strResult+=strTemp;
        pAddrStr = pFixedInfo->DnsServerList.Next;
        while(pAddrStr)
        {
            strTemp.Format("\t\t\t\t%s\n", pAddrStr->IpAddress.String);
                        strResult+=strTemp;
            pAddrStr = pAddrStr->Next;
        }

        strTemp.Format("\tNode Type . . . . . . . . . : ");
                strResult+=strTemp;
        switch (pFixedInfo->NodeType)
        {
            case 1:
                strTemp.Format("%s\n", "Broadcast");
                break;
            case 2:
                strTemp.Format("%s\n", "Peer to peer");
                break;
            case 4:
                strTemp.Format("%s\n", "Mixed");
                break;
            case 8:
                strTemp.Format("%s\n", "Hybrid");
                break;
            default:
                strTemp.Format("\n");
        }
                strResult+=strTemp;

        strTemp.Format("\tNetBIOS Scope ID. . . . . . : %s\n", pFixedInfo->ScopeId);
                strResult+=strTemp;
        strTemp.Format("\tIP Routing Enabled. . . . . : %s\n", (pFixedInfo->EnableRouting ? "yes" : "no"));
                strResult+=strTemp;
        strTemp.Format("\tWINS Proxy Enabled. . . . . : %s\n", (pFixedInfo->EnableProxy ? "yes" : "no"));
                strResult+=strTemp;
        strTemp.Format("\tNetBIOS Resolution Uses DNS : %s\n", (pFixedInfo->EnableDns ? "yes" : "no"));
                strResult+=strTemp;
    } else
    {
        strTemp.Format("GetNetworkParams failed with error %d\n", Err);
                strResult+=strTemp;
        return;
    }

    //
    // Enumerate all of the adapter specific information using the IP_ADAPTER_INFO structure.
    // Note:  IP_ADAPTER_INFO contains a linked list of adapter entries.
    //
    AdapterInfoSize = 0;
    if ((Err = GetAdaptersInfo(NULL, &AdapterInfoSize)) != 0)
    {
        if (Err != ERROR_BUFFER_OVERFLOW)
        {
            AfxMessageBox("GetAdaptersInfo sizing failed with error %d\n", Err);
            return;
        }
    }

    // Allocate memory from sizing information
    if ((pAdapterInfo = (PIP_ADAPTER_INFO) GlobalAlloc(GPTR, AdapterInfoSize)) == NULL)
    {
        AfxMessageBox("Memory allocation error\n");
        return;
    }

    // Get actual adapter information
    if ((Err = GetAdaptersInfo(pAdapterInfo, &AdapterInfoSize)) != 0)
    {
        AfxMessageBox("GetAdaptersInfo failed with error %d\n", Err);
        return;
    }

    pAdapt = pAdapterInfo;

    while (pAdapt)
    {
        switch (pAdapt->Type)
        {
            case MIB_IF_TYPE_ETHERNET:
                strTemp.Format("\nEthernet adapter ");
                break;
            case MIB_IF_TYPE_TOKENRING:
                strTemp.Format("\nToken Ring adapter ");
                break;
            case MIB_IF_TYPE_FDDI:
                strTemp.Format("\nFDDI adapter ");
                break;
            case MIB_IF_TYPE_PPP:
                strTemp.Format("\nPPP adapter ");
                break;
            case MIB_IF_TYPE_LOOPBACK:
                strTemp.Format("\nLoopback adapter ");
                break;
            case MIB_IF_TYPE_SLIP:
                printf("\nSlip adapter ");
                break;
            case MIB_IF_TYPE_OTHER:
            default:
                strTemp.Format("\nOther adapter ");
        }
                strResult+=strTemp;
        strTemp.Format("%s:\n\n", pAdapt->AdapterName);
                strResult+=strTemp;

        strTemp.Format("\tDescription . . . . . . . . : %s\n", pAdapt->Description);
                strResult+=strTemp;

        strTemp.Format("\tPhysical Address. . . . . . : ");
                strResult+=strTemp;
       for (UINT i=0; i<pAdapt->AddressLength; i++)
        {
            if (i == (pAdapt->AddressLength - 1))
                strTemp.Format("%.2X\n",(int)pAdapt->Address[i]);
            else
                strTemp.Format("%.2X-",(int)pAdapt->Address[i]);
                        strResult+=strTemp;
                }        

        strTemp.Format("\tDHCP Enabled. . . . . . . . : %s\n", (pAdapt->DhcpEnabled ? "yes" : "no"));
                   strResult+=strTemp;

        pAddrStr = &(pAdapt->IpAddressList);
        while(pAddrStr)
        {
            strTemp.Format("\tIP Address. . . . . . . . . : %s\n", pAddrStr->IpAddress.String);
                       strResult+=strTemp;
            strTemp.Format("\tSubnet Mask . . . . . . . . : %s\n", pAddrStr->IpMask.String);
                       strResult+=strTemp;
            pAddrStr = pAddrStr->Next;
        }

        strTemp.Format("\tDefault Gateway . . . . . . : %s\n", pAdapt->GatewayList.IpAddress.String);
                   strResult+=strTemp;
        pAddrStr = pAdapt->GatewayList.Next;
        while(pAddrStr)
        {
            strTemp.Format("%52s\n", pAddrStr->IpAddress.String);
                       strResult+=strTemp;
                pAddrStr = pAddrStr->Next;
        }

        strTemp.Format("\tDHCP Server . . . . . . . . : %s\n", pAdapt->DhcpServer.IpAddress.String);
                   strResult+=strTemp;
            strTemp.Format("\tPrimary WINS Server . . . . : %s\n", pAdapt->PrimaryWinsServer.IpAddress.String);
                   strResult+=strTemp;
        strTemp.Format("\tSecondary WINS Server . . . : %s\n", pAdapt->SecondaryWinsServer.IpAddress.String);
                   strResult+=strTemp;

        struct tm *newtime;

        // Display coordinated universal time - GMT
        newtime = gmtime(&pAdapt->LeaseObtained);  
        strTemp.Format( "\tLease Obtained. . . . . . . : %s", asctime( newtime ) );
                   strResult+=strTemp;

        newtime = gmtime(&pAdapt->LeaseExpires);  
        strTemp.Format( "\tLease Expires . . . . . . . : %s", asctime( newtime ) );
                   strResult+=strTemp;

        pAdapt = pAdapt->Next;
    }
        AfxMessageBox(strResult);
}
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


오후 7:33 2008-05-23
web activex/atlcom에서 variant로 인자를 받아야 하는 경우
조경민 bro@shinbiro.com
================================================================


vbscript를 사용하면 인자 전달은 variant로 받도록 하자.


매개 변수 패싱
http://www.ihelpers.co.kr/programming/tipntech.php?CMD=view&IDX=19


매개 변수 패싱 
권고 사항
Out 매개 변수를 Variant로 선언합니다. Visual Basic 용어에서 이것은 By Reference 매개 변


수가 Variant가 되어야 한다는 것을 의미합니다. By Value로 패스된 매개 변수(In 매개 변수)


는 Variant로 제한되지 않지만 Variant와 호환되어야 합니다.


이유
스크립팅 클라이언트는 Variant를 말합니다. COM 서버는 특정 데이터 형식을 말할 수 있습니


다. 특정 데이터 형식 By Value를 COM 서버에 패스할 때, COM 서버는 문제 없이 이들을 수신


합니다. 그러나 이것이 Variant가 아닌 경우, By Reference 인수는 ASP 스크립트에 재전송을


할 수 없습니다.


일반적인 함정
가장 일반적인 오류 중 하나는 Type Mismatch(형식 불일치)입니다. 일반적으로 이것은 By


Reference 변수가 Variant 이외의 것으로서 COM 객체에 패스되기 때문입니다. 일반적인 작업


방식은 By Value 매개 변수를 패스하거나 또는 매개 변수를 Variant로 변경하는 것입니다.


자세한 정보
컴퓨터간에 컴포넌트를 분배하거나 또는 프로세스 외(out-of-process)에서 컴포넌트를 실행한


다면, 매개 변수 By Value를 패스하여 성능 향상을 극대화할 수 있습니다. Passing By


Reference를 패스하면 데이터가 상호간에 전송되어야 하기 때문에 프로세스 또는 컴퓨터간에


더 많은 오버헤드를 발생시킵니다. 매개 변수 By Reference를 패스해야 할 필요가 실제로 없


을 때 매개 변수 By Value를 패스하는 것을 교정과 효율성을 위해서입니다. 기본적으로


Visual Basic은 매개 변수 By Reference를 패스합니다.


다음 KB 기사는 ASP로부터 매개 변수를 COM 객체로 패스하는 방법을 설명합니다.


Q197956 PRB: Passing Parameters By Reference to a VB COM Object (By Reference 매개 변수


를 VB COM 객체로 패스하기) 
Q197957 PRB: Passing Parameters By Reference to a VC COM Object (By Reference 매개 변수


를 VC COM 객체로 패스하기) 


 



Using EntireX DCOM Wrapper Objects with Web Scripting Languages
---------------------------------------
http://documentation.softwareag.com/Crossvision/eli/dcomWrapper/dcomWrapper_webScriptin


g.htm


Scripting languages such as VBScript pass output parameters by VARIANT references, not


as the exactly defined type. For example, when a method of a COM interface has an out


parameter of type string, VBScript passes a reference to a VARIANT to get the out


parameter.

YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


Multiprocessor Considerations for Kernel-Mode Drivers

http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/MP_issues.doc


 

YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


오전 8:28 2008-01-14
조경민 bro@shinbiro.com
Windbg 덤프 분석
=================================================


http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=7978&page=1 에서 정리

drwtsn32.exe 실행
HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug 기록
drwtsn32.exe -i 기본 디버거로 등록


WinDbg실행
File/Open Crash Dump
File/Source File Path설정


Windbg> .symfix+ c:\MySymbol


Windbg> !analyze -v


스레드들의 스택번호
Windbg> kn
스텍 프레임 설정
Windbg>.frame 1
지역변수 보기
Windbg>dv
View/Disassembly (Alt + 7)에서 Offset에 ExceptionAddress: 77f5ec75입력


 

YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


오후 2:44 2007-06-19
FAT Filesystem Long File Name 처리
조경민 bro@shinbiro.com neri.cafe24.com
=================================================================


Long Entry에는 UTF16으로 인코딩된 값이 들어가고
DIR_ENTRY는 DBCS 값이 들어감. (윈도우즈의 파일 시스템을 사용하는 현재 DBCS, 즉 확장 완성형 한글)


예) 가나다Long.txt


가나다의 완성형DBSC값
B0 A1 B3 AA B4 D9
 가    나    다


가나다의 UTF16은
00 AC 98 B0 E4 B2 즉
AC00 B098 B2E4


Long Entry의 Name을 얻어오면
00 AC 98 B0 E4 B2 4C 00 6F 00  .쵖겻콼.o.
 가     나   다     L     o
6E 00 67 00 2E 00 74 00 78 00  n.g...t.x.
  n    g      .     t     x
74 00 00 00
  t    EOS


DIR_ENTRY 의 Name에는 윈도우 기본 한글 완성형 코드 페이지의 DBCS를 넣음
B0 A1 B3 AA B4 D9 7E 31 54 58 54 가나다~1TXT
 가     나    다  ~  1  T  X  T 

'KB > MFC/Win32' 카테고리의 다른 글

[windows] Multiprocessor Considerations for Kernel-Mode Drivers  (0) 2008.03.19
Windbg 덤프 분석  (0) 2008.01.14
FAT Filesystem Long File Name 처리  (0) 2007.06.19
SBSC MBSC Unicode ????  (0) 2007.06.19
PE 헤더 정보  (0) 2006.06.16
Design and Implementation of Power-Aware Virtual Memory  (0) 2006.06.12
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


오전 10:45 2007-06-19
SBSC MBSC Unicode 정리
조경민 bro@shinbiro.com
=======================================================================


참고
--------------------------------------------------------
1. Tong - tigglet님의 STL/C++통
http://tong.nate.com/tigglet/35577610


2. The Complete Guide to C++ Strings, Part I - Win32 Character Encodings
By Michael Dunn.
http://www.codeproject.com/string/cppstringguide1.asp


3. The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About


Unicode and Character Sets (No Excuses!) By Joel Spolsky
http://www.joelonsoftware.com/articles/Unicode.html


4. Character Sets MSDN
http://msdn2.microsoft.com/en-us/library/ms776430.aspx


5. UTF-8 history
http://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt


6. UTF-8 RFC3629
http://www.ietf.org/rfc/rfc3629.txt


7. UNICODE PRIVATE FAQ 0.1 (2004.08.03) by redfrog@jitco.net
http://blog.naver.com/guruby?Redirect=Log&logNo=140004680346


8. Unicode Code Converter v4
http://people.w3.org/rishida/scripts/uniview/conversion.php


http://www.w3c.or.kr/i18n/www-i18n/


http://www.copyeditor.co.kr/reference/char-font/johabwansung.htm


http://blog.naver.com/photo1448?Redirect=Log&logNo=30003683825


http://sparcs.kaist.ac.kr/~jwjung/seminar/hangul-i18n/ko-code.html


http://trade.cbnu.edu/%7Eleesl/code/isounicode.html#1


http://blog.naver.com/k4722?Redirect=Log&logNo=140024341569 (KSC5601)


http://kmh.ync.ac.kr/unix/linuxFAQ/code/


KSSM: 조합형 KSSM 삼보컴퓨터
KSC-5601: 완성형 코드 2232자 (국제표준 ISO-2022, ISO/IEC-10646 호환)
KSC-5657: (국제표준 ISO-2022, ISO/IEC-10646 호환)
EUC-KR: 확장 유닉스코드 변형, 영어는 KSC-5636, 한글은 KSC-5601 사용
MS 통합 완성형(확장 완성형, Unified Hangule, Codepage 949): KSC-5601 호환



character set과 encording
--------------------------------------------------------
character set은 문자 집합, 각 문자당 숫자를 부여한 체계
encording은 컴퓨터상에서 해당 문자를 표현한 상태의 문자집합
예를 들어 완성형한글 KSC5601 codeset (character set)은
Unix에서 euc-kr encording으로 표현되고, Dos에서는 codepage 949로
인코딩되어 표현된다. 윈도우는 기본으로 한글 코드는 완성형 949이다.



1. Single-Byte Character Sets(SBSC) 각 문자는 하나의 바이트
--------------------------------------------------------
한바이트에 총 255개의 문자를 표현 가능 한문자료 표현 가능한 다른 나라말(히브리어, 프랑스


어)등은 code page를 바꾸어서 글짜를 표현.
strlen()등 함수 사용. 마지막 문자는 0.


1.1 ASCII (ISO-8859-1)
ASCII는 7비트(0~127)를 이용하여 영어를 표현 (0x00부터 0x7F)


1.2 OEM Character Sets
IBM PC는 ASCII 한바이트의 안쓰는 상위 비트로 특수 문자(0x80부터 0xFE)를 표현
이 때 코드페이지를 활용해서 한바이트에 총 255개의 문자를 표현 가능
한문자료 표현 가능한 다른 나라말(히브리어, 프랑스어)등은 code page를
바꾸어서 글짜를 표현.
2바이트가 필요한 한국어 같은 아시아 문자는 표현 불가 따라서 MBCS필요.


2. MultiByte Character Sets
--------------------------------------------------------
각 문자가 여러 바이트로 표현되는 문자셋
윈도우에서는 MBCS의 일종으로 DBCS가 있음.
SBSC를 여러바이트로 확장하였고 codepage는 동일하게 존재함.
한글 KSC5601 체계를 위한 codepage 949


2. 1 Double-Byte Character Sets
--------------------------------------------------------
다른 말로 expanded 8-bit character set. SBSC에서 코드페이지를 확장시켜
기존 SBSC에서 중국어 한국어등을 표현하기 위해서 설계됨.
숫자나 영어는 1바이트로, 중국어 한국어 일본어 같은 문자는 2바이트를 하나의 문자로 표현.
윈도우 VC에서는 _MBCS 매크로로 되어 있다.


char s[] = "ABC가나다";
char* p = s;
int codepage = GetACP(); 현재 코드페이지 949 ANSI/OEM - Korean (Unified Hangeul Code)
int len = strlen(s);    // 9 리턴
int len2 = _mbslen((unsigned char*)s); // 6 리턴
while( *p )
{
   p = CharNext( p ); // ABC는 1바이트 전진, 가나다는 2바이트씩 전진
   or
   if( IsDBSCLeadByte(*p ) // 두바이트 문자 선두 바이트면
      p += 2;
   else
      p ++;
}
41 42 43 B0 A1 B3 AA B4 D9 00
A  B  C    가    나    다 


문자열 연산시 strchr이 아닌 _mbschr 등을 써야 함.
마지막 문자는 0 한 바이트.


3. 유니코드
-------------------------------------------------------------
윈도우는 일반적으로 UTF-16을 사용
email이나 xml에서 encording시 UTF-8을 쓸 때가 많음


3.1 UTF-8
UTF-8은 영어 같이 값이 0~126이하(Unicode < 127 )이면 한바이트로 처리하는 방식이다.
윈도우는 기본으로 UTF-16으로 wchar_t가 2바이트를 차지한다.


3.1 UTF-16 or UCS-2
일반적으로 두 바이트를 한 문자로 처리, (영어든 숫자든, 한국어, 중국어)
이렇게 두 바이트를 한 문자로 처리하는 걸 UTF-16또는 UCS-2라고 표현
문자열 연산시 _wcslen()등을 써야 함. 마지막 문자는 00 00 두 바이트임.


wchar_t *p = L"Hello";


Hello 는 다음 과 같음.
U+0048 U+0065 U+006C U+006C U+006F.
메모리 상에
48 00 65 00 6C 00 6C 00 6F 00 00 00
  H     e     l     l     o    EOS


VC에서는 UNICODE(WinAPI용) 과 _UNICODE (표준 c 함수들용)를 함께 정의해야함.



기타


A1. 윈도우 문자셋 지원
----------------------------------------
Win9x는 DBCS로 처리, 유니코드 지원 안함.
WinNT는 유니코드로 처리, DBCS 지원



A2. DBCS에서 문자열 처리 시 주의 사항
----------------------------------------


1. 문자열 이동시 ++, -- 사용 금지
   => CharNext(), CharPrev() 사용


2. 문자열 계산 시 strlen 사용 금지
   => strlen("ABC한글") => 7
      따라서 _mbslen("ABC한글") => 5 해야 알맞게 계산 가능
   => 또는 strchr("ABC한글",'/') 같은거 하면 문자열내에 일본어나
      한국어 중국어에 /와 Ascii코드값이 같은 문자가 포함되어 있을 수 있다.
      따라서 _mbschr("ABC한글",'/') 해야 한다.


3. 문자열 내 위치 계산 시
   => 함부로 pNextChar = pStr + 4; 이렇게 생각하면 안된다.



A3. 유니코드(UTF16) <--> DBCS
----------------------------------------
MultiByteToWideChar()와 WideCharToMultiByte()를 사용


A4. 유니코드(UTF16) <--> UTF8
----------------------------------------
   int WideCharToMultiByte(
      UINT CodePage,            // code page
      DWORD dwFlags,            // performance and mapping flags
      LPCWSTR lpWideCharStr,    // wide-character string
      int cchWideChar,          // number of chars in string
      LPSTR lpMultiByteStr,     // buffer for new string
      int cbMultiByte,          // size of buffer
      LPCSTR lpDefaultChar,     // default for unmappable chars
      LPBOOL lpUsedDefaultChar  // set when default char used
    );


이 함수의 첫번째 매개변수 CodePage에 CP_UTF8를 할당하여 사용합니다.



A5. L""과 한글
----------------------------------------
L""안에 한글을 넣으면 L은 그냥 한글을 분리하여 short으로 만드므로
원하는 결과가 나오지 않는다.


setlocale(LC_ALL, ".949");
wchar_t *wstr2 = L"가나다";
printf("length: %d", wcslen(wstr2)); // 6이 리턴됨.


--- 결과 ---
length: 6
출처 : Tong - tigglet님의 STL/C++통
B0 00 A1 00 B3 00 AA 00 B4 00 D9 00 00 00


setlocale(LC_ALL, ".949");
char *str2 = "가나다";
wchar_t wstr2_uni[blocksize];
memset(wstr2_uni, 0, blocksize * sizeof(wchar_t));
mbstowcs(wstr2_uni, str2, _mbstrlen(str2));


--- wstr2_uni의 메모리 덤프 ---
00 AC 98 B0 E4 B2 00 00
출처 : Tong - tigglet님의 STL/C++통



A6. UTF-8
------------------------------------------
MSN 메신저 개발이나, email content 문자열 처리 등을 하려면 UTF-8 처리 해야한다.


UTF-8은 영어 같이 값이 0~126이하(Unicode < 127 )이면 한바이트로 처리하는 방식이다.
Unicode < 127 0xxxxxxx
Unicode 128 ~ 255 110000xx 10xxxxxx
이렇게 해서 아래처럼 공식화 된다.


   Char. number range  |        UTF-8 octet sequence
      (hexadecimal)    |              (binary)
   --------------------+---------------------------------------------
   0000 0000-0000 007F | 0xxxxxxx
   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx



   The character sequence U+0041 U+2262 U+0391 U+002E "A   TO>." is encoded in UTF-8 as follows:


       --+--------+-----+--
       41 E2 89 A2 CE 91 2E
       --+--------+-----+--


   한국어 U+D55C U+AD6D U+C5B4 is encoded in UTF-8 as follows:
       --------+--------+--------
       ED 95 9C EA B5 AD EC 96 B4
       --------+--------+--------
        
   The character sequence U+65E5 U+672C U+8A9E (Japanese "nihongo",
   meaning "the Japanese language") is encoded in UTF-8 as follows:
  
       --------+--------+--------
       E6 97 A5 E6 9C AC E8 AA 9E
       --------+--------+--------


A7. UTF-16 유니코드 <--> 조합형 한글 처리
------------------------------------------------------
초성 19개, 중성21개, 종성28개(원래 27개 이지만 종성이 없는 경우까지 해서 28개가 된다.)로 총 글자수는 19X21X28 = 11172로서 유니코드에서 지원하는 글자 수와 일치한다.
유니코드에서는 완성된 한글 글자외에도 한글초성, 중성,종성을 따로 정의하고 있다.


자모값을 포함한 하나의 스트링을 받아 한글로 변환하는 방법을 유니코드 버전 2에서 제시하고


있다. 초성, 중성, 종성의 각 인덱스값을 각각 Cho_i, Jung_i, Jong_i로 정의한다면 유니코드


글자값(V)은 다음과 같이 구할 수 있다.


V = { [(Cho_i × 21) + Jung_i] × 28 } + Jong_i + 0xAC00


void IndexToUnicode (unsigned short Cho_i, Jung_i, Jong_i)
{
   unicodeValue = ((Cho_i * 21 + Jung_i)) * 28;
   if(Jong_i)
   {
    unicodeValue += Jong_i + 1;
   }
   unicodeValue += 0xAC00;
}
예:0x1111=ㅍ, 0x1171=ㅟ, 0x11B6=ㅀ {((0 × 21)+0) × 28 + 0 + 0xAC00} = 0xAC00



void toJohab(unsigned short Cho_i, Jung_i, Jong_i)
{
   Cho_i += 2;
   Jung_i += 3;
   if(Jung_i >= 25) Jung+=2;
     /* 중성 인덱스 24, 25는 유니코드에 정의되지 않았음 */
   if(Jung_i >= 18) Jung+=2;
     /* 중성 인덱스 16, 17은 유니코드에 정의되지 않았음 */
   if(Jung_i >= 9)  Jung+=2;
     /* 중성 인덱스 8, 9는 유니코드에 정의되지 않았음 */
   Jong_i += 2;
 
   johabValue = (1 << 15)|(Cho_i << 10)|(Jung_i << 5)|Jong_i;
}


A8. UTF-16 유니코드 초성 중성 종성 분리 코드
-------------------------------------------------------
#include "stdafx.h"
#include
#include
 


    //초성
static const wchar_t wcHead[] = {
           L'ㄱ', L'ㄲ', L'ㄴ', L'ㄷ',          
           L'ㄸ', L'ㄹ', L'ㅁ', L'ㅂ',
           L'ㅃ', L'ㅅ', L'ㅆ', L'ㅇ',
           L'ㅈ', L'ㅉ', L'ㅊ', L'ㅋ',
           L'ㅌ', L'ㅍ', L'ㅎ'};
 
    //중성
static const wchar_t wcMid[] = {
          L'ㅏ', L'ㅐ', L'ㅑ', L'ㅒ',
          L'ㅓ', L'ㅔ', L'ㅕ', L'ㅖ',
          L'ㅗ', L'ㅘ', L'ㅙ', L'ㅚ',
          L'ㅛ', L'ㅜ', L'ㅝ', L'ㅞ',
          L'ㅟ', L'ㅠ', L'ㅡ', L'ㅢ', L'ㅣ'};
 
    //종성
static const wchar_t wcTail[] = {
           L' ', L'ㄱ', L'ㄲ', L'ㄳ',
           L'ㄴ', L'ㄵ', L'ㄶ', L'ㄷ',
           L'ㄹ', L'ㄺ', L'ㄻ', L'ㄼ',
           L'ㄽ', L'ㄾ', L'ㄿ', L'ㅀ',
           L'ㅁ', L'ㅂ', L'ㅄ', L'ㅅ',
           L'ㅆ', L'ㅇ', L'ㅈ', L'ㅊ',
           L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ'};
 
int BreakHan(const wchar_t *str, wchar_t *buffer, UINT nSize)
{
    UINT    pos = 0;
 
    while(*str != '\0')
    {
        if(*str < 256)
        {
            if(pos+2 >= nSize-1) break;
 
            buffer[pos] = *str;
            ++pos;
        }
        else
        {
            if(pos+4 >= nSize-1) break;
 
            buffer[pos]   = wcHead[(*str - 0xAC00) / (21*28)];
            buffer[pos+1] = wcMid[(*str - 0xAC00) % (21 * 28) / 28];
            buffer[pos+2] = wcTail[(*str - 0xAC00) % 28];
 
            pos+=3;
        }
 
        ++str;
    }
 
    buffer[pos] = '\0';
    return pos;
}
 
int GetIndex(int wcType, wchar_t ch)
{
    int Length;
    const wchar_t *pArray;
    switch(wcType) // 초성,중성,종성 배열 : 1,2,3
    {
        case 1 : Length=19;
                 pArray = wcHead;
                 break;
        case 2 : Length=21;
                 pArray = wcMid;
                 break;
        case 3 : Length=28;
                 pArray = wcTail;
                 break;
    }
 
    int k=0;
    for(; k    {
        if( *pArray==ch ) return k;
    }
   
    return -1; // Not Exist
}
 
inline wchar_t ToHan(wchar_t ch1, wchar_t ch2, wchar_t ch3)
{
    int idx1 = GetIndex(1, ch1);
    int idx2 = GetIndex(2, ch2);
    int idx3 = GetIndex(3, ch3);
   
    return (idx1*21*28 + idx2*28 + idx3 + 0xAC00);
}
 
void MergeHan(const wchar_t *buffer, wchar_t *han)
{  
    while(*buffer)
    {
        if(*buffer<256) // 1바이트문자
        {
            *han++ = *buffer++;
        }
        else    // 2바이트 한글.
        {
            if(GetIndex(2, buffer[3])==-1 && buffer[2]>=256) // buffer[3]이 중성(모음)이


아니고
            {                                                // 종성이 2바이트 문자면.. 
                *han = ToHan( buffer[0], buffer[1], buffer[2] );
                ++han;
                buffer+=3;
            }
            else // 모음이면 종성으로 ' '보냄
            {
                *han = ToHan( buffer[0], buffer[1], L' ' );
                ++han;
                buffer+=2;
            }
        }
    }
    *han=0;
}
 
#define printf TRACE
int Test_main()
{
    wchar_t *str = L"나는 한AB국CD을 사랑합니다...";
    wchar_t buffer[4096];
 
    setlocale(LC_ALL, "Korean");  // DBSC 완성형 한글 코드 페이지 선택
 
    printf("원본문자열 :%S\n", str);
 
    BreakHan(str, buffer, sizeof buffer);    
    printf("분리문자열 :%S\n", buffer);
 
 
    wchar_t recover[1024];
    MergeHan(buffer, recover);
    printf("복원문자열 :%S\n", recover);
 
 
    wchar_t test1[] = L"ㄱㅏㄴㅡㄴ ㅅㅔㅇㅝㄹ ㄱㅡ ㄴㅜㄱㅏ";
    wchar_t test2[] = L"ㄱㅏaㄴㅡㄴ ㅅㅔabcㅇㅝㄹ ㄱㅡ  ㄴㅜㄱㅏ"; 
 
    MergeHan(test1, recover);
    printf("복원문자열 :%S\n", recover);
   
    MergeHan(test2, recover);
    printf("복원문자열 :%S\n", recover);
 
 
    return 0;
}


원본문자열 :나는 한AB국CD을 사랑합니다...
분리문자열 :ㄴㅏ ㄴㅡㄴ ㅎㅏㄴABㄱㅜㄱCDㅇㅡㄹ ㅅㅏ ㄹㅏㅇㅎㅏㅂㄴㅣ ㄷㅏ ...
복원문자열 :나 는 한AB국CD을 사 랑합니 다 ...
복원문자열 :가는 세월 그 누가
복원문자열 :가a는 세abc월 그  누가


A9. DBCS나 MBCS에서 두바이트 이상 문자는 bigendian에서도 같나?
-----------------------------------------------------------------------------------------------


두바이트가 하나의 문자를 표현할때, big endian cpu에서도 little때 처럼
첫번째 바이트를 Lead 바이트로 보고 다음 바이트를 Tail 바이트로 처리
하면 된다.
즉, 두바이트라고 해서 short 값으로 표현하는게 아니다. char ch[2]인것이다.

'KB > MFC/Win32' 카테고리의 다른 글

Windbg 덤프 분석  (0) 2008.01.14
FAT Filesystem Long File Name 처리  (0) 2007.06.19
SBSC MBSC Unicode ????  (0) 2007.06.19
PE 헤더 정보  (0) 2006.06.16
Design and Implementation of Power-Aware Virtual Memory  (0) 2006.06.12
IGlobalInterfaceTable  (0) 2006.03.24
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


PE 헤더 정보

KB/MFC/Win32 2006.06.16 01:00
#ifndef __PE_H__
#define __PE_H__
/*
        2006/06/16
        PE Header from winnt.h
        by bro (Kyung min, Cho) bro@shinbiro.com
        http://neri.cafe24.com
*/

/*
  DOS 헤더 (IMAGE_DOS_HEADER)
  DOS Stub 코드
  PE 헤더 (IMAGE_FILE_HEADER)
  Optional Header (IMAGE_OPTIONAL_HEADER32)
  Section 헤더들 (IMAGE_SECTION_HEADER)
  섹션1 (RAW DATAS)
  섹션2
*/

/*
        유용한 정보들
        IMAGE_DOS_HEADER.e_lfanew : PE헤더의 시작위치 이미지 file offset
        IMAGE_DOS_HEADER.e_lfanew에서 'PE..' 4자리 다음이 PE 헤더(IMAGE_FILE_HEADER)임
        IMAGE_FILE_HEADER = IMAGE_DOS_HEADER.e_lfanew + 4('PE  ')

        PE 헤더 다음에 Optional Header가 있고 이 Optional Header에
        IMAGE_OPTIONAL_HEADER32.ImageBase : 이미지가 로드되어야 할 가상 주소
        IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint : EntryPoint RVA
        만일 재배치(Relocation) 없다면 ImageBase + AddressOfEntryPoint가 실제 가상주소
        
        Optinal Header다음에 Section 헤더들이 있다.
        Section 헤더 갯수는 IMAGE_FILE_HEADER.SizeOfOptionalHeader임
*/

typedef unsigned char        BYTE;
typedef unsigned short        WORD;
typedef        unsigned long        DWORD;
typedef        long                        LONG;

// from winnt.h
#define IMAGE_DOS_SIGNATURE                 0x4D5A      // MZ
#define IMAGE_OS2_SIGNATURE                 0x4E45      // NE
#define IMAGE_OS2_SIGNATURE_LE              0x4C45      // LE
#define IMAGE_NT_SIGNATURE                  0x50450000  // PE00

//////////////////////////////////////////////////////////////////////
// DOS 헤더
//////////////////////////////////////////////////////////////////////
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header (PE header)
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

// pe header
//////////////////////////////////////////////////////////////////////
// PE 헤더
//////////////////////////////////////////////////////////////////////
typedef struct _IMAGE_FILE_HEADER {
        //DWORD 'PE'
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

#define IMAGE_SIZEOF_FILE_HEADER             20


#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE

//
// Directory format.
//

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

//
// Optional header format.
//

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;                // 처음 실행할 RVA 주소
        // 재배치 안할경우 실제 가상 주소 : ImageBase + AddressOfEntryPoint
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;                                        // /base: 시작 주소
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER    224
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b

typedef IMAGE_OPTIONAL_HEADER32             IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32            PIMAGE_OPTIONAL_HEADER;
#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER     IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
#define IMAGE_NT_OPTIONAL_HDR_MAGIC         IMAGE_NT_OPTIONAL_HDR32_MAGIC

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef IMAGE_NT_HEADERS32                  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32                 PIMAGE_NT_HEADERS;

// IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is the same either way.

#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER)        \
    ((ULONG_PTR)ntheader +                                              \
     FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) +                 \
     ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader   \
    ))
// Subsystem Values

#define IMAGE_SUBSYSTEM_UNKNOWN              0   // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE               1   // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI          2   // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI          3   // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI              5   // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI            7   // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8   // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9   // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION      10  //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11   //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER   12  //
#define IMAGE_SUBSYSTEM_EFI_ROM              13
#define IMAGE_SUBSYSTEM_XBOX                 14

// DllCharacteristics Entries

//      IMAGE_LIBRARY_PROCESS_INIT           0x0001     // Reserved.
//      IMAGE_LIBRARY_PROCESS_TERM           0x0002     // Reserved.
//      IMAGE_LIBRARY_THREAD_INIT            0x0004     // Reserved.
//      IMAGE_LIBRARY_THREAD_TERM            0x0008     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_NO_BIND     0x0800     // Do not bind this image.
//                                           0x1000     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER  0x2000     // Driver uses WDM model
//                                           0x4000     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000

// Directory Entries

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor
//
// Section header format.
//

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

#define IMAGE_SIZEOF_SECTION_HEADER          40

//
// Section characteristics.
//
//      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
//      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.
//      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.
//      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.
//      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.

#define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.

#define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.
#define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.
//      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.
#define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.
//                                           0x00002000  // Reserved.
//      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA                0x00008000
//      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000
#define IMAGE_SCN_MEM_PURGEABLE              0x00020000
#define IMAGE_SCN_MEM_16BIT                  0x00020000
#define IMAGE_SCN_MEM_LOCKED                 0x00040000
#define IMAGE_SCN_MEM_PRELOAD                0x00080000

#define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //
#define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //
#define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //
#define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //
#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //
#define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //
#define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //
#define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //
#define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //
#define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //
#define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //
#define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //
#define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //
// Unused                                    0x00F00000
#define IMAGE_SCN_ALIGN_MASK                 0x00F00000

#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section is executable.
#define IMAGE_SCN_MEM_READ                   0x40000000  // Section is readable.
#define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section is writeable.


#endif//__PE_H__

--------------------------
static CString BroGetFile( CString sFilter )
{
        CFileDialog fd( TRUE, NULL, NULL, NULL, sFilter );
        if( IDCANCEL == fd.DoModal() )
                return "";
        return fd.GetPathName();
}

void CTestPEDlg::OnGetPeInfo()
{
        // TODO: Add your control notification handler code here
        static char BASED_CODE szFilter[] = "Executable Files (*.exe)|*.exe|DLL Files (*.dll, *.ocx)|*.dll;*.ocx|All Files (*.*)|*.*||";
        CString sImage;

        sImage = BroGetFile(szFilter);
        if(sImage == "")
                return;

        int nPEHeaderOffset;
        int nReaded;
        FILE* fp;
        fp = fopen( sImage, "rb" );
        
        IMAGE_DOS_HEADER idh;

        nReaded = fread( &idh, sizeof(idh), 1, fp );
        if( nReaded != 1 )
        {
                AfxMessageBox("[ERROR] fread( buf, sizeof(IMAGE_DOS_HEADER), 1, fp )");
                fclose(fp);
                return;
        }
        
        if( idh.e_magic != 'ZM' )        // check 'MZ'
        {
                AfxMessageBox("[ERROR] DOS signature error");
                fclose(fp);
                return;
        }
        
        nPEHeaderOffset = idh.e_lfanew;

        if( 0 != fseek( fp, nPEHeaderOffset, SEEK_SET ) )
        {
                AfxMessageBox("[ERROR] seek( fp, SEEK_SET, nPEHeaderOffset )");
                fclose(fp);
                return;
        }

        DWORD pe_sig;
        nReaded = fread( &pe_sig, sizeof(pe_sig), 1, fp );
        if( nReaded != 1 )
        {
                AfxMessageBox("[ERROR] fread( buf, sizeof(pe_sig), 1, fp )");
                fclose(fp);
                return;
        }
        if( pe_sig != 'EP' ) // 'PE  ' signature check
        {
                AfxMessageBox("[ERROR] PE signature error");
                fclose(fp);
                return;
        }

        IMAGE_FILE_HEADER ifh;
        nReaded = fread( &ifh, sizeof(ifh), 1, fp );
        if( nReaded != 1 )
        {
                AfxMessageBox("[ERROR] fread( buf, sizeof(IMAGE_FILE_HEADER), 1, fp )");
                fclose(fp);
                return;
        }

        IMAGE_OPTIONAL_HEADER ioh;
        nReaded = fread( &ioh, sizeof(ioh), 1, fp );
        if( nReaded != 1 )
        {
                AfxMessageBox("[ERROR] fread( buf, sizeof(IMAGE_OPTIONAL_HEADER), 1, fp )");
                fclose(fp);
                return;
        }

        DWORD dwEntryPoint;
        dwEntryPoint = ioh.ImageBase + ioh.AddressOfEntryPoint;
        
        CString sOut;
        CString sLine;
        sLine.Format( "dwEntryPoint : %x\n", dwEntryPoint );
        sOut += sLine;

        int nSectionNumbers = ifh.NumberOfSections;

        sOut += "section info----------\n";
        for( int i = 0 ; i < nSectionNumbers ; i ++)
        {
                IMAGE_SECTION_HEADER ish;
                nReaded = fread( &ish, sizeof(ish), 1, fp );
                if( nReaded != 1 )
                {
                        AfxMessageBox("[ERROR] fread( buf, sizeof(IMAGE_SECTION_HEADER), 1, fp )");
                        fclose(fp);
                        return;
                }

                sLine.Format("name: %s \nbase: 0x%08x\nsize: 0x%08x\n",
                        ish.Name, ioh.ImageBase + ish.VirtualAddress, ish.SizeOfRawData );
                
                sOut += sLine;
        }
        
        AfxMessageBox(sOut);
        fclose(fp);
}

'KB > MFC/Win32' 카테고리의 다른 글

FAT Filesystem Long File Name 처리  (0) 2007.06.19
SBSC MBSC Unicode ????  (0) 2007.06.19
PE 헤더 정보  (0) 2006.06.16
Design and Implementation of Power-Aware Virtual Memory  (0) 2006.06.12
IGlobalInterfaceTable  (0) 2006.03.24
COM 스레드 모델 STA, MTA  (0) 2006.03.24
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


Design and Implementation of Power-Aware Virtual Memory
----------------------------------------------------------
http://www.usenix.org/events/usenix03/tech/full_papers/huang/huang_html/index.html

'KB > MFC/Win32' 카테고리의 다른 글

SBSC MBSC Unicode ????  (0) 2007.06.19
PE 헤더 정보  (0) 2006.06.16
Design and Implementation of Power-Aware Virtual Memory  (0) 2006.06.12
IGlobalInterfaceTable  (0) 2006.03.24
COM 스레드 모델 STA, MTA  (0) 2006.03.24
원격 프로세스 제어 (원격 스레드 생성)  (0) 2006.02.01
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


IGlobalInterfaceTable

Allows any apartment in a process to get access to an interface implemented on an object in any other apartment in the process. The three methods allow you to do the following:
프로세스 내의 어떤 아파트먼트에서든 어떤 다른 아파트먼트안에서 구현된 객체의 인터페이스를 접근할 수 있도록 한다.

Register an interface as a global (processwide) interface.
Get a pointer to that interface from any other apartment through a cookie.
Revoke the global registration of an interface.
The IGlobalInterfaceTable interface is an efficient way for a process to store an interface pointer in a memory location that can be accessed from multiple apartments within the process, such as processwide variables and agile (free-threaded marshaled) objects containing interface pointers to other objects.
프로세스 전역 인터페이스로 등록한다.
각 다른 아파트먼트는 쿠키값으로 구분하여 등록된 인터페이스의 포인터를 얻는다.


An agile object is unaware of the underlying COM infrastructure in which it runs—in other words, what apartment, context, and thread it is executing on. The object may be holding on to interfaces that are specific to an apartment or context. For this reason, calling these interfaces from wherever the agile component is executing may not always work properly. The global interface table avoids this problem by guaranteeing that a valid proxy (or direct pointer) to the object is used, based on where the agile object is executing.

The global interface table is not portable across process or machine boundaries, so it cannot be used in place of the normal parameter-passing mechanism.

Note   IGlobalInterfaceTable is available on Microsoft® Windows NT® 4.0, Service Pack 3 and later. It is also available on Microsoft Windows® 95 with DCOM version 1.1 and later.

When to Implement
You should not implement this interface. The standard implementation provides complete thread-safe functionality.

When to Use
Use this interface when an interface implemented on an object in one apartment must be stored in memory accessible for use by other apartments. To create the global interface table object and get a pointer to this interface, make the following call:

CoCreateInstance(CLSID_StdGlobalInterfaceTable,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IGlobalInterfaceTable,
                            (void **)&gpGIT)

Note   When creating the global interface table object using the above call, you must link to the library Uuid.lib. This will resolve the external symbols CLSID_StdGlobalInterfaceTable and IID_IGlobalInterfaceTable.

There is a single instance of the global interface table per process, so all calls to this function in a process return the same instance.

After calling the CoCreateInstance function, register the interface you want to make available processwide from the apartment in which it resides with a call to the RegisterInterfaceInGlobal method. This supplies a pointer to a "cookie" (through the pdwCookie parameter) that identifies the interface and its location. An apartment that wants a pointer to this interface then calls the GetInterfaceFromGlobal method with this cookie, and the implementation then supplies an interface pointer to the calling apartment. To revoke the interface's global registration, any apartment may call the RevokeInterfaceFromGlobal method.

A simple example of its use would be when you want to pass an interface pointer on an object in a single-threaded apartment (STA) to a worker thread in another apartment. Rather than having to marshal it into a stream and pass the stream to the worker thread as a thread parameter, this interface allows you simply to pass a cookie.

When you register the interface in the global interface table, you get a cookie that you can use instead of passing the actual pointer whenever you need to pass the pointer either to a nonmethod parameter that is going to another apartment (as a parameter to ThreadProc via CreateThread) or to in-process memory accessible outside your apartment.

Care is required because using globals places the extra burden on the programmer of managing problems such as race conditions and mutual exclusion, which are associated with accessing global state from multiple threads simultaneously.

Methods in Vtable Order
IUnknown Methods Description
QueryInterface Returns pointers to supported interfaces.
AddRef Increments the reference count.
Release Decrements the reference count.
IGlobalInterfaceTable Methods Description
RegisterInterfaceInGlobal Permits access to a given interface from any apartment in a process.
RevokeInterfaceFromGlobal Revokes the registration of a global (processwide) interface.
GetInterfaceFromGlobal Gives the calling apartment access to an interface registered as global.

Requirements
  Windows NT/2000/XP: Requires Windows NT 4.0 SP3 or later.
  Windows 95/98: Requires Windows 98 (or Windows 95 with DCOM 1.2).
  Header: Declared in objidl.h.

'KB > MFC/Win32' 카테고리의 다른 글

PE 헤더 정보  (0) 2006.06.16
Design and Implementation of Power-Aware Virtual Memory  (0) 2006.06.12
IGlobalInterfaceTable  (0) 2006.03.24
COM 스레드 모델 STA, MTA  (0) 2006.03.24
원격 프로세스 제어 (원격 스레드 생성)  (0) 2006.02.01
TCP 성능 향상  (0) 2006.01.31
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


http://blog.naver.com/zacronan?Redirect=Log&logNo=40018174412
http://airtight.yonsei.ac.kr/research/COM/thread_apartment.htm

1-2 스레딩 모델

먼저 이 부분을 설명하기 위해서는 아파트먼트(Apartment)라는 것에 대해 설명이 필요하다. 아파트먼트는 하나의 프로세스 내에서 여러 개의 스레드를 가지고 각각의 스레드 동기화 문제를 해결하기 위해 나온 것으로 각 오브젝트를 가지고 있는 하나의 방이라는 개념으로 이해하면 된다. 각 아파트먼트당 하나의 스레드가 존재하며 오브젝트는 적당한 아파트먼트 안으로 들어가게 된다.

이러한 스레딩 모델(Threading Model)은 레지스트리에서 CLSID의 스레딩 모델의 값을 보면 된다. 가능한 경우는 스레딩 모델이 아예 없거나 아파트먼트, 프리(Free), 보스(Both)가 되는 것이다. 아파트먼트는 STA 모델을 가리키며 프리는 MTA 모델을, 보스는 STA, MTA 둘 다 지원한다는 것을 말한다. 이 값이 아예 없다는 것은 main STA에서 동작한다는 것을 말하고 이 main STA는 프로세스가 초기에 주 스레드에서 호출한 CoInitializeEx 값에 의해 결정된다.




① STA(Single Threaded Apartment)

STA 내에서 서버는 각각의 아파트먼트 내에 각 오브젝트가 존재하며 하나의 프로세스 내에서 각 아파트먼트 내에 각 오브젝트가 들어가 있게 된다. 이 경우는 CoInitializeEx(NULL,COINIT_APARTMENTTHREADED)를 각각의 스레드당 호출하여 초기화 된다. 이러한 각각의 오브젝트 호출은 메시지에 의해 동기화 된다. 즉 이러한 메시지를 통해 동기화 된다는 것은 메시지 루프를 가져야 한다는 얘기이다.

하나의 아파트먼트 내에서는 프록시의 개입 없이 직접적으로 호출할 수 있으나 다른 아파트먼트 내에서는 이렇게 될 수는 없다. 즉 하나의 메소드 호출은 클래스 네임이 OleMainThreadWndClass를 가지는 윈도우 클래스가 등록한 WndProc로 가서 적당한 Interface의 메소드를 호출하게 된다. 이러한 모델 내에서의 호출은 그림 5와 같다.










그림 5 : STA에서의 메시지 큐


그림 5에서 보는 것처럼 서버로의 모든 호출은 큐(Queue) 속에서 들어가며 GetMessage,DispatchMessage에 의해 해당 오브젝트로 전달된다.




② .MTA(Multi Threaded Apartment)

MTA 내에서 하나의 아파트먼트 내에 여러 개의 스레드와 오브젝트가 들어가게 되며 따라서 오직 한 번만 CoInitializeEx(NULL, COINIT_MULTITHREADED)를 호출하면 된다. 이 경우에는 여러 개의 스레드가 동시에 오브젝트의 메소드로 접근할 수 있기 때문에 Reentrant하도록 소스가 작성되거나 동기화 문제를 코드 안에서 해결해야 한다. 하지만 서버 안에서의 스레드간 인터페이스 전달에 프록시가 개입할 필요가 없다.

또한 STA로 작성하는 것보다 빠른 속도를 보이는 멀티 스레드의 장점을 충분히 활용할 수

가 있으며 하나의 프로세스 내에 오직 하나의 MTA만 만들어질 수 있다.




③ 혼합 모델

이 모델은 프로세스가 한 개의 MTA와 한 개 이상의 STA를 가진다는 것을 의미한다.




④ STA와 MTA와 혼합 모델에서의 선택

어떤 오브젝트의 모델을 선택하는 것은 각기 장단점이 존재하기 때문에 상황에 맞게 선택해야 하는데, STA에서는 프로그래머가 스레드간의 동기화를 신경쓸 필요가 없다. 그러나 여기서 다른 아파트먼트로 인터페이스를 전달하기 위해서는 프록시의 개입을 필요로 하므로 느려질 수 있으며, 또한 객체로의 메소드 호출이 메시지 루프(Loop)를 통해 한번에 하나씩 만 처리되기 때문에 멀티 스레드의 장점을 충분히 활용할 수가 없게 된다.

그러나 MTA를 선택한 경우 서버 객체의 구현자는 여러 개의 스레드가 동시에 메소드 호출을 수행할 수가 있으므로 코드는 Reentrant하게 작성되거나 Mutex, Critical Section, Event를 통해 동기화 코드를 작성해야 한다. 따라서 작성이 어려워지게 되지만 이 경우라고 해도 수많은 사용자가 사용할 수 있는 오브젝트라면 한번 고려해볼 만하다.
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


요즘 좋은 기술 많이 나오네요 ㅇ_ㅇ;;

Remote Library:
http://www.codeproject.com/win32/remote.asp#xx1150183xx
번역:
http://www.devpia.com/forum/BoardView.aspx?no=7262&ref=7262&page=1&forumname=vc_lec&stype=


어셈블리로 된 보다 안정된 녀석이라는데..

1. Internal 9x functions must be called by thread that owns certain system mutexes (~ runs on system level).
2. NtAlocateVirtualMemory should be called inside __try/__except frame (Nt's VirtualAllocEx is implemented that way).
3. Did you test your code under Win95 and 9x debug builds? (No).
4. What about Win95 OS 2.1+?
5. What about 9x remote thread into 16bit process?
6. What about 9x remote thread into not-yet-initialized process? (DllMains get called with THREAD_ATTACH before PROCESS_ATTACH).
When DebuActiveProcess or OpenProcess in 9x are hooked via IAT+GPA or EAT pointer replacement,
your solution will not work.

http://www.anticracking.sk/EliCZ/export/CPRPICHA.zip

'KB > MFC/Win32' 카테고리의 다른 글

IGlobalInterfaceTable  (0) 2006.03.24
COM 스레드 모델 STA, MTA  (0) 2006.03.24
원격 프로세스 제어 (원격 스레드 생성)  (0) 2006.02.01
TCP 성능 향상  (0) 2006.01.31
ATL COM 로컬 서버 Keep Alive 시키기  (0) 2006.01.06
DCOM with xp sp2  (0) 2006.01.06
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


TCP 성능 향상

KB/MFC/Win32 2006.01.31 11:49
오전 10:05 2006-01-31
조경민 bro@shinbiro.com
TCP 성능 향상
====================================================================


Piggy-back
request - response 통신 중 일때 수신측에서 잘 받았다는 ACK를 따로 전송하지 않고
response 보내기 시에 header의 ACK 필드를 사용하여 ACK를 response 패킷에 함께 보내는 방식

Nagle 알고리즘
작은 양의 데이터를 여러번 send() 호출로 보내는 경우 네트워크 효율이 좋지 못하여
send()를 여러번 호출해도 일정 기간동안 지연해서 TCP 스택의 보내기 버퍼에 쌓아둔 후
한번에 보내는 알고리즘


INFO: Design Issues - Sending Small Data Segments Over TCP w/Winsock
--------------------------------------------------------------------

데이터 패킷을 받게 되면 잘 받았다고 TCP 스택은 ACK 메시지를 보내게 되는데,
Microsoft TCP 스택은 200ms delay 타이머가 다운 카운드 되게 된다.

- delay timer가 expire되기 전에 두번째 데이터 패킷을 받게 되면 ACK를 보낸다.
- (두번째 데이터 패킷이 도착되거나 delay timer가 expire되기) 전에 데이터를 또 보내
게 되면 ACK는 데이터 패킷에 piggy-back(등에 엎혀서)되어 함께 보내진다.
- delay timer가 expire되면 ACK가 보내진다.

작은 데이터 패킷들로 네트웍이 혼잡해지는 것을 피하기 위해서 Microsoft TCP 스택은
Nagle 알고리즘을 기본적으로 사용하게 되는데, 작은 데이터를 여러번 send 호출하면
작은 데이터 들은 TCP 스택 보내기 버퍼에 쌓이게 되고 이전에 보낸 데이터 패킷이
상대방에서 받아졌다는 ACK가 나올때 까지 지연되었다가 한번에 보내진다.
아래는 nagle 알고리즘이 적용안되는 예외 상황이다.

- 만일 스택에 Maximum Transmission Unit (MTU)보다 큰 데이터 버퍼가 쌓였다면
상대측으로 부터 ACK를 기다리지 않고 즉시 full-sized packet(한 패킷)을 보내게 된다.
- TCP_NODELAY 소켓 옵션이 적용되어 Nagle 알고리즘이 비활성화되면 작은 데이터 패킷들은
지연없이 바로 상대방으로 보내진다. 따라서 각 작은 데이터 send 마다 즉각즉각 ACK가
날아온다. 하지만 한번에 쌓아서 보낼 수 없어 효율적이지 못하다.

애플리케이션 상에서 성능을 최적화하기 위해서 Winsock은 애플리케이션에서 send 호출시
Winsock kernel 보내기 버퍼에 복사해 둔다. 그런 후, tcp 스택은 Nagle 알고리즘같은
학습된 지능적인 방식으로 네트워크 상에 패킷을 실제 보내야 할 시기를 결정한다.
SO_SNDBUF 옵션으로 할당된 윈속 커널 보내기 버퍼의 크기(기본 8K)를 변경할 수 있다.
대부분 경우, 애플리케이션에서 보내기 완료라는 것은 애플리케이션 send 호출로 데이터
버퍼가 윈속 tcp 스택 보내기 커널 버퍼에 복사되었다는 것을 알려주는 것일 뿐이며,
네트워크 상에 패킷이 발생되었다는 것을 알려주는 것은 아니다. 이 보내기 완료의 의미가
다른 딱 하나의 상황은 SO_SNDBUF를 0으로 설정하여 Winsock 버퍼링을 비활 성화한 경우이다.

Winsock은 다음 규칙에 따라 애플리케이션에게 보내기가 완료되었음을 알려준다.
- 소켓 보내기가 아직 SO_SNDBUF 보내기 버퍼 할당 크기내에 있으면 윈속은 애플리케이션에서
send한 데이터를 보내기 버퍼에 복사하여 쌓아두고 애플리케이션에게 보내기가 완료되었다고
알려준다.
- 소켓이 SO_SNDBUF 범위 이상을 보내려 하고, 이전에 쌓아진(buffered) 하나의 send가 스택
커널 버퍼에 있다면, 윈속은 애플리케이션 send 데이터를 복사해 오고, 애플리케이션에게 보내기
완료를 알려준다.
- 소켓이 SO_SNDBUF 범위를 넘어 있고, 이전에 쌓아진 하나 이상의 send가 스택 커널버퍼에
있다면 윈속은 애플리케이션 send로 부터 데이터를 복사한다. 윈속은 소켓이 SO_SNDBUF에 다시
데이터를 채울 수 있을때까지 애플리케이션에게 보내기 완료를 발생시키지 않는다.
즉 SO_SNDBUF가 0이 아닌 상황에서 스택 보내기 버퍼가 꽉차지 않았다면 애플리케이션 send()는
스택 보내기 버퍼에 복사하여 쌓아둔 후 보내기가 완료되었다고 말한다.

Case Study 1
TCP 클라이언트가 10000 레코드를 TCP 서버에 데이터베이스 저장을 위해서 보낸다.
레코드의 크기는 20바이트에서 100바이트로 가변적이다. 다음과 같이 애플리케이션이 짜여져있다.
- 클라이언트는 blocking send만 하며, server는 blocking recv만 한다.
- 클라이언트는 SO_SNDBUF를 0으로 하여 하나의 데이터 버퍼에 각 레코드들을 보낸다.
  (TCP 스택 버퍼를 사용하지 않고 하나의 사용자 버퍼로 각 레코드를 담아 여러번 send()를 한다.)
- 서버는 loop를 돌면서 recv()를 호출한다. 200바이트 버퍼를 recv()에 넣어 각 recv()호출로
  각 레코드를 받는다.

성능: 테스트결과 서버로 일초에 5개의 레코드만 보낼 수 있었다. 총 10000 레코드를 보내는데
최대 976K 바이트의 데이터(10000*100/1024)를 보내는 것인데 30분이상이 소요되었다.

분석: 클라이언트에서 TCP_NODELAY 옵션을 설정하지 않아 TCP 스택은 Nagle 알고리즘에 따라
다른 send() 패킷을 네트웍상에 바로 보내지 않고 ACK를 기다리고 ACK가 오면 쌓인 버퍼를
보내게 된다. 그러나 SO_SNDBUF = 0으로 클라이언트가 winsock 버퍼링을 사용하지 않는다 하였으므로
10000 send() 호출은 각각 네트웍 상으로 보내져야 하고 매번 ACK를 받아야 한다.
각 ACK는 아래 서버의 TCP 스택에서 발생되는 일로 200ms 지연이 된다.
- 서버는 패킷을 받고 200ms delay timer를 다운 카운트 한다.
- 서버는 어떤 것도 response할 것이 없기 때문에 ACK은 piggyback되지 못한다.
- 서버에서 delay timer가 expire되어 ACK가 클라이언트로 전송된다.

향상: 두가지 설계적인 문제가 있다. 첫째로 delay timer 문제가 있는데 클라이언트는 200ms지연
내에 서버로 두개이상의 패킷을 보낼 필요가 있다. 클라이언트는 기본적으로 Nagle 알고리즘을
사용하기 때문에 SO_SNDBUF를 0으로 설정하지 않게 하여 기본 윈속 버퍼링을 사용하게 하면 된다.
TCP 스택이 Maximum Transmission Unit(MTU)보다 큰 버퍼로 쌓이게 되면 상대측으로 ACK를 기다리지
않고 즉시 한번에 full-sized 패킷을 보내게 된다.
두번째로 이런 설게에서 작은 레코드들 마다 send()를 호출하였다. 작은 데이터를 보내는 것은
매우 효율적이지 못하다. 이런 경우 각 데이터 레코드를 100바이트로 pad(작은 데이터도 더미 데이터를
붙여) 만들어 한번에 80 레코드들을 send() 시킬 수 있다. 얼마나 많은 레코드를 보냈는지 서버에서
알 수 있도록 클라이언트는 레코드 묶음을 보내기 전에 고정 크기의 헤더에 레코드 갯수를 담아 보낼 수 있다.

Case Study 2
윈속 TCP 클라이언트는 두개의 TCP 연결을 연 후, 상품 견적 서비스를 제공하려 한다.
첫번째 연결은 서버로 상품 번호를 보내는 명령 채널로 사용되고, 두번째 연결은 상품 견적을
받는 데이터 채널로 사용된다. 두 채널은 연결된 후, 클라이언트는 서버로 상품 번호를 보내고
데이터 채널에서 데이터가 올때까지 기다리게 된다. 처음 상품 견적이 받아진 후에야 서버로
다음 상품 번호를 보낸다. 클라이언트와 서버는 모두 SO_SNDBUF와 TCP_NODELAY 옵션을 설정하지 않았다.

성능: 테스트 결과 초당 5개의 견적을 받을 수 있었다.

분석: 이 설계에서는 한번에 하나의 상품 견적 요청만 가능하다. 첫번째 상품 번호가 명령채널을 통해
서버로 보내지고 response는 서버에서 클라이언트로 데이터 채널을 통해 바로 보내진다. 그러면
클라이언트는 즉시 두번째 상품 번호 요청을 보내기 위해 윈속 보내기 버퍼에 복사된다.
그러나 클라이언트 TCP 스택은 커널 버퍼에 있는 요청을 바로 보내지 못한다. 첫번째 명령 채널로
보낸 send에 대한 ACK가 아직 안왔기 때문이다. 서버 명령 채널의 200ms delay timer 후 expire되어
첫번째 상품 번호 요청에 대한 ACK를 클라이언트에게 보내게 된다. 그러면 두번째 견적 요청은
200ms 지연후 서버로 보내지게 된다. 두번째 상품 번호에 대한 견적 응답은 데이터 채널로 바로
오게 되는데 이 당시는 클라이언트 테이터 채널의 delay timer가 expire되었기 때문이다.
서버는 이전 견적 응답에 대한 ACK를 받은 것이다. 클라이언트는 200ms 동안 두번째 상품 견적 요청을
보내지 못하여 클라이언트의 delay timer의 expire에 의해 ACK가 서버로 보내지게 된 것이다.
결과적으로 클라이언트는 두번째 견적 응답을 받고 다른 견적 요청을 하지만 같은 방식으로 지연이 이뤄진다.

향상: 두개의 연결 채널을 맺는 것은 여기서 필요치 않다.만일 한개의 연결만 맺고, request, response를
하였다면 request에 대한 ACK는 response에 piggyback되어 함께 돌아올 수 있다.
더 향상된 방식으로 클라이언트는 여러개의 요청을 한번에 보내고 서버도 역시 여러개의 응답을
한번에 보낼 수 있다. 만일 두개의 단방향 채널 설계가 필요하다면 두 채널에 TCP_NODELAY 옵션을
주어 작은 패킷을 이전 패킷의 ACK가 올때까지 기다리게 하지 말고 바로 바로 보낼 수 있게 하면된다.

권고: 위 두가지 경우는 꾸며진 상황이다. 최악의 상황을 설명하기 위해서이다.

- 만일 데이터 세그먼트가 time critical하지 않다면 애플리케이션은 하나의 큰 데이터 블럭으로
묶은 다음 한번의 send()를 하라. 너무 크지 않은 버퍼여야 하는데 8K이하면 항상 효율적이다.
윈속 보내기 버퍼가 MTU보다 크다면 보내기 버퍼내 한번에 보낼 수 있는 패킷 크기안의 여러
full-sized 패킷을 보내고 마지막 패킷은 남겨진다. 마지막 패킷을 제외하고는 200ms delay timer
지연을 받지 않는다. 마지막 패킷이 홀수 번째 패킷이면 지연된 ACK 알고리즘과 관련되고
보내기 스택 끝에 MTU 범위를 넘는 다른 보내야할 블럭이 있다면 이는 Nagle 알고리즘으로 처리된다.
- 가능하다면 단방향 데이터 흐름의 연결을 피해야한다. Nagle과 지연된 ACK 알고리즘의 악영향을
받게 된다.
- 만일 작은 데이터 세그먼트를 즉시 보내야 한다면 TCP_NODELAY 옵션을 보내는 쪽에서 설정한다.
- 만일 윈속이 보내기 완료를 알려주는 것이 네트워크 상에 패킷이 실제 보낸 것이라는 것을
보장하길 원치 않는다면 SO_SNDBUF를 0으로 설정하지 말아야 한다. 즉, SO_SNDBUF를 0으로
설정한다면 네트웍상으로 패킷을 보낸 것을 보내기 완료로 윈속이 알려준다는 의미이다.
SO_SNDBUF가 0이 아닌 값이면 보내기 완료는 TCP 스택 버퍼에 복사되어 쌓인것을 의미한다.
보내기 버퍼의 8K 버퍼 크기는 대부분의 상황에서 잘 동작되도록 설정된 값이라 더 나은 성능을
보이는 상황 테스트를 하지 않은 이상 변경하지 말아야 한다.
SO_SNDBUF를 0으로 하는 것은 벌크 데이터 전송에 성능 이득을 준다. 최대 효율을 위해서
더블 버퍼링(하나 이상의 보내기 버퍼를 묶음)과 Overlapped I/O를 함께 사용해야 한다.
- 만일 데이터 전달이 신뢰성을 보장받지 않아도 된다면 UDP를 사용하라.

참고 :
Common Performance Issues in Network Applications Part 1: Interactive Applications
이 문서에서 TCP같은 Stream형 프로토콜의 Overlapped I/O를 사용하는 경우만 SO_SNDBUF = 0
를 추천하고 있다.

'KB > MFC/Win32' 카테고리의 다른 글

COM 스레드 모델 STA, MTA  (0) 2006.03.24
원격 프로세스 제어 (원격 스레드 생성)  (0) 2006.02.01
TCP 성능 향상  (0) 2006.01.31
ATL COM 로컬 서버 Keep Alive 시키기  (0) 2006.01.06
DCOM with xp sp2  (0) 2006.01.06
ShowWeb function  (0) 2004.05.24
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


오후 8:29 2006-01-05
bro@shinbiro.com 조경민
ATL COM 로컬 서버 Keep Alive 시키기
============================================================

COM 클라이언트의 Release() 호출로 서버의 object reference와
IClassFactory의 LockCount가 0이 되면 Com server는 자동으로 release된다.
즉, COM 서버 프로세스가 죽게 된다. 이를 막고 싶으면 아래 처럼 한다.


1. 서비스 타입이 아닌 COM 로컬 서버인 경우

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
    HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
       :
        _Module.m_nLockCnt++;    // 추가
        _Module.Start();
}

강제로 모듈의 내부 Lock Count를 증가시켜 아래와 같이 unlock이 일어나
WM_QUIT가 발생되는 것을 막는다.

LONG CServiceModule::Unlock()
{
    LONG l = CComModule::Unlock();
    if (l == 0 && !m_bService)
        PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
    return l;
}


2. 서비스 타입인 경우

Comserver.exe /service
하면 서비스로 등록되며, 서비스는 위 서비스 모듈 Unlock() 소스 처럼
WM_QUIT가 발생되지 않는다.

'KB > MFC/Win32' 카테고리의 다른 글

원격 프로세스 제어 (원격 스레드 생성)  (0) 2006.02.01
TCP 성능 향상  (0) 2006.01.31
ATL COM 로컬 서버 Keep Alive 시키기  (0) 2006.01.06
DCOM with xp sp2  (0) 2006.01.06
ShowWeb function  (0) 2004.05.24
[펌] band object에서 IWebBrowser 인터페이스 받기.  (0) 2004.05.12
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


DCOM with xp sp2

KB/MFC/Win32 2006.01.06 20:17
오후 8:17 2006-01-06
DCOM with xp sp2 조경민 bro@shinbiro.com
===================================================

sp2가 설치되지 않은 상황
--------------------------------------------------------------
client (xp nosp2, incops, dsn)
regsvr32 TCSps.dll
testapp.exe 실행

server (xp nosp2, incops, no dsn)
regsvr32 TCSps.dll
TCS.exe /regserver


원격 시작 권한 설정(서버, no sp2)
---------------------------------------------------------------
시작->설정->제어판->관리도구->구성 요소 서비스->
콘솔 루트->구성 요소 서비스->컴퓨터->내컴퓨터->DCOM 구성->
TSSCORE 오른클릭 속성->보안->시작 권한 사용자 지정 후 Everyone 추가


sp2를 설치한 컴퓨터
---------------------------------------------------------------

1. 방화벽 설정( sp2를 설치한 서버 또는 클라이언트 )

1.1 커맨드창을 열고 다음 명령어를 입력한다.
netsh
firewall
set service REMOTEADMIN ENABLE SUBNET 또는
set service REMOTEADMIN ENABLE ALL
show service
exit

1.2 DCOM 방화벽 포트 열기
방화벽을 끄거나, 제어판/윈도우즈 방화벽의 탭중 예외에 RPC인 135 포트를 추가하거나 프로그램에서
자신의 Local DCOM Server EXE를 선택한다.

sp2를 설치한 서버
---------------------------------------------------------
다음으로 제어판/관리도구로 간 후 구성 요소 서비스를 연 후
트리 노드 루트/컴퓨터/내컴퓨터에서 오른클릭 속성으로 간 후 COM 보안에서
각각 제한값 편집 버튼을 눌러 사용자 'ANOYMOUS LOGIN' 추가 후 ANOYMOUS LOGIN을 모두 허용하게 만든다.

아래는 마지막으로 DCOM 서버가 할 이다.
구성 요소 서비스의 트리  루트 노드/컴퓨터/내컴퓨터/DCOM 구성에서 자신의 DCOM 서버를 선택한 후
오른클릭 속성으로 등록정보를 연후 보안탭을 연후 시작 및 활성화 권한을 사용자 지정으로 한후 편집 버튼
을 누른 후 ANONYMOUS LOGON을 추가후 모두 허용으로 한다.

'KB > MFC/Win32' 카테고리의 다른 글

TCP 성능 향상  (0) 2006.01.31
ATL COM 로컬 서버 Keep Alive 시키기  (0) 2006.01.06
DCOM with xp sp2  (0) 2006.01.06
ShowWeb function  (0) 2004.05.24
[펌] band object에서 IWebBrowser 인터페이스 받기.  (0) 2004.05.12
메세지 크래커  (0) 2004.04.29
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


ShowWeb function

KB/MFC/Win32 2004.05.24 15:14
ShowWeb Function
2004-05-24 조경민 bro ( bro@shinbiro.com )
==================================================
웹브라우저 새창, 기존창, 팝업창, 숨은창으로 띄우는 함수

typedef enum
{
        BROWSE_SELF = 0,
        BROWSE_NEW,
        BROWSE_POPUP,
        BROWSE_HIDE
}BROWSE_TYPE;

CString GetPopupURL( LPCTSTR url, int width, int height )
{
        TCHAR szTempPath[MAX_PATH];
        GetTempPath( MAX_PATH, szTempPath );
        // 임시 파일을 만든다.
        TCHAR szTempShortName[MAX_PATH];
        ZeroMemory( szTempShortName, sizeof(szTempShortName) );
        GetTempFileName(szTempPath, _T("bro"), 0, szTempShortName);
        
        TCHAR szTempName[MAX_PATH];
        ZeroMemory( szTempName, sizeof(szTempName) );
        GetLongPathName( szTempShortName, szTempName, MAX_PATH );
        // 생성된 임시파일의 File URL을 리턴한다.
        CString sURL;
        sURL.Format(_T("file://%s"), szTempName );
        
        CString sHTML;
        sHTML.Format(_T(" \
<HTML><SCRIPT language='VBScript'> \r\n\
Sub WIndow_OnLoad \r\n\
  Call Window.Open( \"%s\" , \"\",\"height=%d, width=%d, toolbar=0\", true) \r\n\
End Sub \r\n\
</SCRIPT> \r\n\
<BODY> \r\n\
</BODY> \r\n\
</HTML>"), url, height, width );

        HANDLE hTempFile;
        hTempFile = CreateFile((LPTSTR) szTempName, GENERIC_READ | GENERIC_WRITE,  
                                        0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);                        // no attr. template
        DWORD dwWritten;
        WriteFile( hTempFile, (LPCTSTR)sHTML, (DWORD)sHTML.GetLength(), &dwWritten, NULL );
        CloseHandle(hTempFile);

        return sURL;
}

//==============================================================
// 함수명 : ShowWeb
// 설  명 : 새로운 창으로 웹 브라우저를 띄운다.
// 인  자 : type = 0 self, = 1 new, = 2 popup
// 리턴값 :
//--------------------------------------------------------------
// 작성일     작성자            작성이유
// 2002-11-20 조경민                                Jiransoft(c)
//==============================================================
void ShowWeb( LPCTSTR url, BROWSE_TYPE type /*= BROWSE_SELF*/ )
{
        static bool _first = true;

        if( _first || type == BROWSE_NEW )
        {
                // 새창으로 띄우기
                ShellExecute( NULL, "open", "iexplore.exe",url, NULL, SW_SHOWNORMAL);
                _first = false;
        }
        else
        if( type == BROWSE_POPUP )
        {
                // popup 창으로 띄우기
                ShellExecute( NULL, "open", "iexplore.exe",GetPopupURL( url ), NULL, SW_HIDE);
        }
        else
        if( type == BROWSE_HIDE )
        {
                // hide 무조건 안보이게만 띄우기
                ShellExecute( NULL, "open", "iexplore.exe", url , NULL, SW_HIDE);
        }
        else
        //if( type == BROWSE_SELF )
        {
                // 기존창으로 띄우기
                ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
        }
}

'KB > MFC/Win32' 카테고리의 다른 글

ATL COM 로컬 서버 Keep Alive 시키기  (0) 2006.01.06
DCOM with xp sp2  (0) 2006.01.06
ShowWeb function  (0) 2004.05.24
[펌] band object에서 IWebBrowser 인터페이스 받기.  (0) 2004.05.12
메세지 크래커  (0) 2004.04.29
[DB] ODBC 데이타소스 생성하기 (DSN 생성)  (0) 2004.04.28
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


티스토리 툴바