티스토리 뷰

프로그래밍/API

API 아톰 ATOM

에어버스 2016. 8. 6. 17:19
API 아톰 ATOM

아톰 테이블

시스템이 유지하는 문자열 테이블

응용프로그램이 아톰 테이블에 문자열을 보관해 놓으면 저장된 문자열을 대표하는 16비트 정수값을 돌려주는데 이 핸들을 아톰이라고 한다. (32비트 환경에서 모든 핸들이 32비트로 업그레이드 되었지만 아톰만은 아직 16비트이다.)

아톰 테이블이 등록되면 응용 프로그램은 언제든지 아톰으로부터 문자열을 얻을 수 있다. 핸들은 단순한 정수값이며 메시지를 통해 응용 프로그램끼리 교환할 수 있으므로 아톰은 기초적인 IPC의 수단으로 사용 가능하다.

응용 프로그램이 아톰을 직접 사용하는 경우는 드물며 주로 DDE에서 아이템, 토픽 이름 문자열 교환을 위해 내부적으로 사용된다. 또한 윈도우 클래스나 클립보드 포맷도 내부적으로 아톰 테이블에 저장된다.

종류

 로컬 아톰 테이블

 테이블을 만든 응용 프로그램 내에서만 사용 가능하다.
 중목된 문자열을 정수형 아톰으로 치환해서 메모리 절약
 신속한 문자열 검색을 위해 사용
 이런 경우 용도로 사용하는 경우 거의 없어 실용성은 별로 없다.

 글로벌 아톰 테이블

 시스템의 모든 응용 프로그램이 같이 사용할 수 있다.
 IPC에 사용

문자열 아톰

0xC000 ~ 0xFFFF 까지 범위 사용, 대소문자 구분은 저장되기는 하지만 문자열 비교에는 사용되지 않으며 부분 문자열 검색은 지원되지 않는다. 최대 255바이트의 길이까지 가능하다. 참조 카운트가 유지되므로 여러 응용 프로그램이 같은 이름으로 아톰을 등록할 수 있다.

정수형 아톰

0x0 ~ 0xBFFF 까지 범위를 가진다. #dddd 형태로 저장되며 참조 카운터는 유지되지 않는다. 정수형 아톰을 만들려면 MAKEINTATOM 매크로 함수를 사용한다. MAKEINTATOM 은 정수를 (WORD)(DWORD)로 캐스팅하여 (LPCTSTR)로 캐스팅하는 간단한 캐스팅 매크로이다.

로컬 아톰 테이블에 문자열을 추가, 삭제 함수

ATOM AddAtom(LPCTSTR lpString); // 암톰값을 리턴
ATOM DeleteAtom(ATOM nAtom);

정수 아톰을 추가하려면 MAKEINTATOM 매크로 함수를 사용하면 된다. AddAtom(MAKEINTATOM(123));

이미 테이블에 들어 있는 문자열 아톰을 중복 추가한 경우 AddAtom()는 새로운 아톰을 만들지 않고 참조 회수만 1 증가 시킨다. DeleteAtom()는 참조 회수룰 1 감소 시키며 참조 회수가 0이 될때 문자열을 아톰 테이블에서 제거한다.

읽고자 하는 아톰과 문자열 버퍼를 주면 아톰 테이블에서 문자열을 읽어 버퍼에 채운다.
UINT GetAtomName(ATOM nAtom, LPSTR lpBuffer, int nSize);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static ATOM AtStr, AtX, AtY;
    TCHAR str[128], temp[128];
    int x, y;
    case WM_CREATE:
        AtStr = AddAtom(TEXT("Atom Test String"));
        AtX = AddAtom(MAKEINTATOM(123));
        AtY = AddAtom(MAKEINTATOM(50));
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
            GetAtomName(AtStr, str, 128);
            GetAtomName(AtX, temp, 128);
            x = _wtoi(temp + 1); // 정수 앞에 # 이 붙어 #을 제외 시키기 위해 +1 한다.
            GetAtomName(AtY, temp, 128);
            y = _wtoi(temp + 1);
            TextOut(hdc, x, y, str, lstrlen(str));
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        DeleteAtom(AtStr);
        DeleteAtom(AtX);
        DeleteAtom(AtY);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
cs

 

 

 

 

 

 

 

 

 

 

아톰은 DDE 에서 사용되나 거의 쓸 일이 없다.

 

글로벌 아톰 (다른 프로그램에 문자열 전달)

ATOM GlobalAddAtom(LPCTSTR lpString);
ATOM GlobalDeleteAtom(ATOM nAtom);
UINT GlobalGetAtomName(ATOM nAtom, LPTSTR lpBuffer, int nSize);

GlobalAddAtom()로 문자열을 글로벌 아톰 테이블에 추가한 후 아톰값을 메시지나 기타 다른 방법으로 다른 응용프로그램에 전달하면 GlobalGetAtomName()를 사용하여 아톰값으로부터 문자열을 추출할 수 있다.

아톰을 이용한 문자열 교환은 약속된 위치에 데이터를 저장해 놓고 이 데이터를 찾을 수 있는 핸들만 알려주는 식이다.

ATOM FindAtom(LPCTSTR lpString);
ATOM GlobalFindAtom(LPCTSTR lpString);

문자열로부터 아톰 값을 구해내는 함수들이다.

아톰의 동작 원리는 비교적 간단하므로 다방면으로 손쉽게 활용할 만하지만, 일종의 시스템 공유 메모리로 구현되기 때문에 네트워크를 통한 원격 통신에는 사용할 수 없으며 연속적인 통신에 사용하기는 무척 어렵다는 단점이 있다. 컴퓨터 내부에서 일회적인 통신에만 사용하는 것이 적합하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define WM_ATOM WM_USER+1
ATOM Atom;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HWND hlPCAtom2;
    TCHAR* Msg = TEXT("왼쪽 버튼을 누르면 아톰으로 문자열을 전달 합니다.");
    switch (message)
    {
    case WM_CREATE:
        Atom = GlobalAddAtom(TEXT("Atom Test String"));
        break;
    case WM_LBUTTONDOWN:
        hlPCAtom2 = FindWindow(NULL, TEXT("IPCAtom2"));
        if (hlPCAtom2)
            SendMessage(hlPCAtom2, WM_ATOM, Atom, 0);
        else
            MessageBox(hWnd, TEXT("메시지를 전달할 윈도우가 없습니다."), TEXT("에러"), MB_OK);
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
            TextOut(hdc, 1050, Msg, lstrlen(Msg));
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        GlobalDeleteAtom(Atom);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
cs

IPCAtom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define WM_ATOM WM_USER+1
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static TCHAR str[128];
    switch (message)
    {
    case WM_ATOM:
        GlobalGetAtomName((ATOM)wParam, str, 128);
        InvalidateRect(hWnd, NULL, TRUE);
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
            TextOut(hdc, 10100, str, lstrlen(str));
            EndPaint(hWnd, &ps);
        }
        break;
...
}
cs

 

윈도우 클래스 아톰

시스템이 문자열 저장을 위한 용도로 종종 사용된다.

ATOM RegisterClass(CONST WNDCLASS* lpWndClass);

이 함수는 윈도우 클래스를 아톰 테이블에 등록하고 윈도우 클래스 아톰을 리턴한다. 대개의 경우 이 리턴값은 무시하지만 이 아톰을 저장해 놓았다가 윈도우를 생성하거나 윈도우 클래스를 등록 취소할 때 사용할 수 도 있다.

ATOM atClass = RegisterClass(&WndClass);
HWND hWnd = CreateWindow((LPCTSTR)atClass, lpszClss, WS_OVERLAPPEDWINDOW,...);

CreateWindow()의 첫번째 인수로 클래스 아톰을 전달하면 해당 클래스로 윈도우가 생성된다. 물론, 윈도우 클래스 이름을 지정하는 것이 더 편리하기 때문에 이런 식으로 윈도우를 생성하는 경우는 거의 없지만 아톰이 이런 용도로 사용된다는 것도 참고로 알아두자. 시스템 전역 클래스 중 #32770, #32768 등의 클래스들은 아톰 형태로 정의되어 있는 것들이다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
ATOM atom;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR    lpCmdLine, _In_ int       nCmdShow)
{
...
    atom = MyRegisterClass(hInstance);
    TCHAR str[128];
    GetAtomName(atom, str, lstrlen(str));
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
...
}
 
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT4));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WIN32PROJECT4);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassExW(&wcex);
}
 
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
 
   HWND hWnd = CreateWindowW((LPCTSTR)atom /*szWindowClass*/, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
...
}
cs

33행에서 클래스 등록하고 이 리턴받은 아톰값으로 40행에서 윈도우를 만들때 이용해도 된다.

7행에서 디버깅하면 str 값은 아래 그림처럼 알 수 없는 값만 들어 있다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28