http://ezbeat.tistory.com/444 (Windows Clipboard : OpenClipboard)
저번글에 이어 이번엔 GetClipboardData 함수가 어떻게 동작하는지 알아보겠습니다.
2. GetClipboardData(CF_TEXT)
역시나 MSDN 설명
클립보드의 지정된 포맷으로부터 데이터를 검색한다고 되어 있습니다.
인자로 들어간 값이 클립보드 포맷입니다. 수십가지의 표준 포맷이 있지만 여기선 텍스트 포맷을 사용하였습니다.
텍스트 포맷 : 라인의 끝은 (CR-LF) 결합으로 되어 있고, 데이터 끝은 NULL로 되어 있습니다. ANSI 만 가능!
유니코드로 사용하려면 CF_UNICODETEXT 사용!
아무튼 함수 설명은 이러합니다. 코드를 보면 알 수 있듯이 리턴 값은 포인터인데 해당 포인터엔 클립보드에서 가져온 데이터가 있습니다. 출력출력!
이제 내부적으로 어떻게 동작하는지 알아봐야겠네요.
먼저 GetClipboardData 가 User영역에서 어떻게 동작하는지를 알아보겠습니다.
어셈코드를 쭉 봐봤는데 대충 이렇게 작동합니다.
1. hData = NtUserGetClipboardData( CF_TEXT, pClipData ) 호출, 호출 후 pClipData에는 현재 클립보드 상태가 담겨짐
2. pClipData.uFmtRet 값이 CF_TEXT 와 비교
3-1. CF_TEXT 와 같은 경우 user32의 전역변수인 RTL_CRITICAL_SECTION 구조체 변수 gcsClipboard 를 인자로 크리티컬 섹션 진입
3-2. user32의 전역변수인 클립보드 구조체 변수 gphn 체이닝 확인
3-3-1. gphn 체이닝이 있는 경우 해당 체이닝을 뒤져서 해당 포맷에 맞는 데이터를 리턴
3-3-2. gphn 체이닝이 없는 경우 힙 할당하고 힙에 포맷, hData, 메모리 핸들 등을 초기화해서 체이닝에 등록
이 때, hData를 인자로 CreateLocalMemHandle 함수를 쓰면 포맷(CF_TEXT)에 맞는 클립보드 내용을 담은 메모리 값을
리턴 = hMem
4-1. CF_TEXT와 비교결과 다른고 CF_UNICODETEXT인 경우
4-2. CreateLocalMemHandle 함수로 해당 CF_UNICODETEXT에 맞는 메모리 내용을 가져오고 WideCharToMultiByte를 사용해 유니코드를 ANSI로 변경 후 CF_TEXT 포맷 데이터 위치에 값 쓰고 다시 얻어와서 리턴!
[먼말인지 잘 이해가 안가실탠데 간단하게 요약하겠습니다.]
클립보드 관리는 커널에 있는 스테이션이라는 커널오브젝트에서 관리를 하게 됩니다.
이 때 클립보드는 여러가지 기본 포맷을 가지는데요. CF_TEXT, CF_UNICODETEXT, CF_BITMAP 등등.. 이런 포맷에 맞게 각각의 데이터 공간을 가지고 있습니다.
reactOS 코드 일부입니다.
PCLIP static FASTCALL
IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj, UINT fmt)
{
unsigned i = 0;
for (i = 0; i < pWinStaObj->cNumClipFormats; ++i)
{
if (pWinStaObj->pClipBase[i].fmt == fmt)
return &pWinStaObj->pClipBase[i];
}
return NULL;
}
이 함수는 윈도우 스테이션 오브젝트에서 해당 클립보드 포맷에 맞는 클립보드 베이스 주소를 가져오는 함수입니다.
이처럼 윈도우 스테이션은 클립보드 포맷 개수와 각 포맷에 있는 베이스 주소를 가지고 있습니다. 하나의 클립보드 공간을 전부 공유하는 형태가 아니라는 것입니다.
저희가 notepad.exe를 켜고 "test" 라는 단어를 쓴 다음 Ctrl+C로 복사를 하게되면 이는 CF_UNICODETEXT 포맷의 클립보드 영역에 저장이됩니다. 하지만 프로그램에서 CF_TEXT로 클립보드 내용을 요청하면 CF_UNICODETEXT 포맷의 클립보드 영역에 있는 값을 가져와 ANSI로 변환 후 CF_TEXT 클립보드 영역으로 복사하고 그 내용을 보여주는 것입니다.
그리고 CF_TEXT를 인자로주어 클립보드 내용을 변경시켜도 당연히 CF_UNICODETEXT 포맷의 클립보드 영역은 그대로 입니다. 실제로 CF_TEXT 를 인자로주어 클립보드 내용을 "Ezbeat" 으로 변경시켜고 Ctrl+V를 눌러보시면 "test" 가 그대로 나오는 것을 보실 수 있을 것입니다.
아래는 GetClipboardData 함수 작동 메커니즘을 순서도로 나타낸 그림입니다.
( 출처 : Extracting the Windows Clipboard from Physical Memory )
원본에는 없지만 색은 제가 넣어봤습니다. 연두색으로 표시된 부분은 user 영역입니다.
커널까지 더욱 깊게 분석을 해봐야하지만 시간이 없어 여기까지만 하겠습니다.
'My Study > Programming&Theory' 카테고리의 다른 글
Driver에서 ZwReadVirtualMemory 사용하기 (0) | 2013.06.30 |
---|---|
PsSetLoadImageNotifyRoutine 과 ZwAllocateVirtualMemory (4) | 2013.06.20 |
Windows Clipboard : OpenClipboard (2) | 2013.06.03 |
ERROR C4996 (8) | 2013.05.23 |
Bug Check 0x9A : SYSTEM_LICENSE_VIOLATION (2) | 2013.05.04 |