뭉근 : 느긋하게 타는 불

PsSetCreateProcessNotifyRoutineEx를 실행하면 아래와 같이 STATUS_ACCESS_DENIED(0xc0000022) 에러가 반환된다.

   

ObCallbackTest: DriverEntry: Driver loaded. Use ed nt!Kd_IHVDRIVER_Mask f (or 7) to enable more traces

ObCallbackTest: DriverEntry: PsSetCreateProcessNotifyRoutineEx(2) returned 0xc0000022

   

이상하게 MS측에서 제공하는 드라이버 샘플 파일은 접근 거부가 일어나지 않는데, 내가 직접 똑같은 소스코드를 사용하여 컴파일한 드라이버를 로드할 경우에는 저 에러가 떴다.

   

MS에 의하면 PsSetCreateProcessNotifyRoutineEx는 Highest Level 드라이버에서만 동작한다고 되어 있어서 드라이버도 권한이 있는건가 싶어서 계속 알아보았는데 아무것도 안나왔다. 따라서 소스코드 문제인가 싶어 WDM, KMDF 드라이버 등을 생성하여 여러 방면으로 함수 호출을 시도해보았지만 문제가 해결되지 않았다.

   

그러나 위의 에러 문구를 검색하니 정말 간단한 문제 해결 방법이 나왔다.

링커 옵션에 INTEGRITYCHECK 옵션을 넣어주면 되는 것이다.

   

다음과 같이 프로젝트 속성의 링커 옵션을 추가해주면 된다.

   

   

아래는 obcallback 샘플의 링커 옵션이다.

   

   

   

INTEGRITYCHECK 옵션이란 메모리 메니저가 PE Header의 플래그값을 확인하여 드라이버 이미지를 로드하기 위하여 디지털 시그너처를 검사하는 것이다. MS에 의하면 모든 드라이버들이 이 기능을 사용하길 추천한다고 명시되어 있다.

   

integritycheck를 검색해보니 이 기능을 사용하지 않을 경우 일부 API를 사용할 수 없다고 한다.

'프로그래밍' 카테고리의 다른 글

Rstudio 3.3.0 스케일링 문제  (0) 2016.05.06
드라이버 개발 삽질 #1  (0) 2015.03.12
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
CPP 벡터 반복문 중 원소 지우기  (0) 2014.09.22

Rstudio 3.3.0을 깔고 실행했더니

아래 그림과 같이 폰트 사이즈나 리소스 크기 등이 굉장히 불편하게 되어 있었다.

   

   

처음엔 Rstudio 버그인가 싶어서 resolution, window size, resource bug 등의 키워드로 검색해보았는데 대부분 plot 부분의 resolution을 처리하는 방법에 대한 문서들만 나왔다. 문득 떠오른 생각이 Rstduio 설치 할 때 QT 라이브러리도 같이 설치했던 기억이 나서 이 문제인가 싶어서 검색해보았더니 QT의 high resolution 지원으로 인한 스케일링 문제인 것으로 알 수 있었다. 몇 번의 검색 시도 끝에 다음과 같은 해결 방법이 있는 문서를 찾았다.

   

Qt fully supports high DPI monitors from Qt 5.6 onward, via attribute or environment variable (except on OS X where support is native). For the attribute method, use:

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support

QApplication app(argc, argv);
return app.exec();
}

or set the system environment variable:

QT_AUTO_SCREEN_SCALE_FACTOR=1

I've tested both methods on windows 10 with a high-DPI surfacebook monitor and the results are scaled properly as expected.

   

출처: <http://stackoverflow.com/questions/24367355/automatic-rescaling-of-an-application-on-high-dpi-windows-platform>

   

시스템 환경변수에서 저 부분을 변경하려고 들어갔더니 QT_DEVICE_PIXEL_RATIO가 2로 설정되어 있었다. 뜻을 보니 딱 스케일링 관련 환경 변수같아서 다음과 같이 1로 설정하였더니 문제가 해결되었다.

   

   

아래는 잘 실행되는 Rstudio이다

   

   

- 요약

시스템 환경 변수의 QT_DEVICE_PIXEL_RATIO 값을 확인하여 1이 아닌 값으로 되어 있을 경우 1로 변경

* QHD, UHD 등이 고해상도 환경에서는 이 부분의 배율을 조정하여 눈에 편하게 볼 수 있을 것 같다.

'프로그래밍' 카테고리의 다른 글

PsSetCreateProcessNotifyRoutineEx 접근 권한 문제  (1) 2016.05.10
드라이버 개발 삽질 #1  (0) 2015.03.12
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
CPP 벡터 반복문 중 원소 지우기  (0) 2014.09.22

1. vmware를 이용한 드라이버 디버깅 방법

데브구루의 기술 칼럼을 따라했는데 잘 되지 않았다.

프로젝트 생성한 후, 호스트가 윈도우 7 x64이고 타겟이 가상머신 윈도우 7 x86인 환경에서

디버깅 환경 설정을 진행하였는데 드라이버 컴파일 후 가상 머신으로 전송하고 Driver Install 하는 부분에서 막혔다.

이후 타겟을 윈도우 8.1 x64로 변경하였는데 잘되었다.

컴파일 설정은 당연히 바꾸고 했는데 이상했다... 

아무튼 디버깅을 해보니 타겟으로 Driver Install 하는데 시간도 오래 걸리고 디버깅하는데도 버벅 거렸다.

간단한 제작에는 DbgPrint 등으로 디버깅하는게 더 빠르겠다.


참고
http://devguru.co.kr/blog/6619/

https://msdn.microsoft.com/en-us/library/windows/hardware/hh439654(v=vs.85).aspx



2. WinDbg에 DbgPrint 출력하기

DbgPrint 출력 전에 WinDbg 커맨드 라인에 아래와 같이 해주면 된다.

kd> ed Kd_DEFAULT_MASK 8


3. 커널 페이지 메모리 보호 해제

MDL을 사용하여 페이지 메모리 보호 해제를 하려다 

예전에 공부한 CR0 레지스터 변경을 찾아서 적용했더니 바로 되었다.

짬내어 MDL 공부도 해놓아야겠다.


참고 

http://resources.infosecinstitute.com/hooking-system-service-dispatch-table-ssdt/


4. 드라이버 로드 & 언로드 1

윈도우 서비스 메니저(SCM)을 이용하여 로드까진 진행이 잘 되었는데

드라이버를 언로드하려 할 때 아래 코드에서 자꾸 에러가 났다.

ControlService(service, SERVICE_CONTROL_STOP, &ss)

알고보니 드라이버 언로드 루틴이 없어서 그런거였다.

또는 MJ_IRP_CLOSE 루틴인가? .. 사실 언로드 루틴과 클로즈 루틴을 다 넣어놨다.

뭐 때문인지는 테스트해봐야겠지만 일단 그냥 둔다.


참고

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682571(v=vs.85).aspx


5. 드라이버 로드 & 언로드 2

이번엔 드라이버가 처음에는 잘 로드되는데

처음 로드한 드라이버를 언로드 후 다시 로드하면 시스템 에러 0x02가 났다.

확인해보니 디바이스 생성 후 삭제를 안해서 

커널에 똑같은 이름의 디바이스가 남아있었다.

드라이버 언로드 루틴에 디바이스 오브젝트 삭제 코드를 추가하였다.


실행 상태(SERVICE_RUNNING)인 드라이버를 언로드하기 위해서는 반드시

QueryServiceStatusEx를 호출하여 서비스 실행 상태를 얻고

실행 중이면 ControlService를 이용해 중지 명령을 내려야 한다.

(일부 드라이버는 delete pending에 들어가 재부팅 후에만 제대로 언로드가 될 수 있다.)


참고

IOCTL 예제 코드(https://code.msdn.microsoft.com/IOCTL-a583bbeb?SRC=VSIDE)

* VS2013에서는 New Project 다이얼로그의 Online - Samples에서 바로 컴파일 가능한 형태로 다운받을 수 있다.


6. 디바이스 핸들 얻기

CreateFile을 이용하여 디바이스 핸들을 얻기 위해서 드라이버에 반드시 추가해야할 코드가 있다.

첫번째는 IoCreateDevice, IoCreateSymbolicLink, IoDeleteSymbolicLink, IoDeleteDevice 함수 셋이다.

이 함수들이 뭐냐하면 디바이스를 생성하고 생성한 디바이스에 대해 유저 영역(Win32)에서 디바이스로 접근할 수 있는 이름을 생성하는 것이다.

IoCreateDevice에서 인자로 넣어주는 이름은 디바이스 이름이고, IoCreateSymbolicLink에서 넣어주는 이름은 유저 핸들 이름(?)이라 할 수 있겠다.

꼭 이렇게 해주고 드라이버 언로드 루틴에서 디바이스와 심볼릭 링크를 삭제해야 다음 로드시 드라이버 로드가 된다.

두번째는 IPR_MJ_CREATE와 IRP_MJ_CLOSE이다. 이 함수가 드라이버에 등록되지 않으면 CreateFile로 핸들 생성 자체가 안된다.

예전에 디폴트 커널 코드가 있다고 알고 있었는데 없어졌나 싶다.

(IRP_MJ_CLOSE는 아닐 수도 있다... 테스트할 시간이 없다.)


0. 드라이버 개발에 좋은 도구들

devicetree : 디바이스가 제대로 등록되어 있는지 확인할 수 있다.

osrloader : 등록한 드라이버가 서비스에 등록되어 있는지 확인할 수 있다.

winobj : 디바이스와 디바이스의 심볼릭 링크가 있는 전역이름공간(\\??\, 즉 \\.\)을 확인할 수 있다.


계속 추가 예정이다.

'프로그래밍' 카테고리의 다른 글

PsSetCreateProcessNotifyRoutineEx 접근 권한 문제  (1) 2016.05.10
Rstudio 3.3.0 스케일링 문제  (0) 2016.05.06
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
CPP 벡터 반복문 중 원소 지우기  (0) 2014.09.22

wofstream을 사용하여 로그를 기록하는데 이상하게 한글만 출력이 안되었다. 입력 버퍼에도 잘 기록되었는데 안되다니 뭔가 이상했다. 출력된 로그 파일을 보니 영문과 숫자까지만 출력이 되고 그 뒤로 출력되어야할 한글 문자열부터 출력이 되지 않았다. 궁금해서 헥스 편집기로 열어서 보니 아래와 같이 아스키코드로 저장되어 있는 것을 확인할 수 있었다.

   

   

이 무슨 어이없는 일이란 말인가? wofstream으로 출력했으니 당연히 wide 문자로 나와야한다고 생각했는데 큰 오산이었다. 뭐 결국에 해결하고 생각해보면 당연한게 wofstream은 wchar_t 형태의 문자열을 파일로 출력하는 클래스기 때문에 파일 최적화를 위해서 굳이 wchar_t 형태로 내보낼 필요가 없다는 것이다.

wofstream에서 한글 출력을 설정하기 위해서는 코드에 간단하게

   

std::locale::global(std::locale("Korean"));

   

를 추가하면 된다. 하지만 코드의 어디다 넣어야 될까? 파일 쓰기 함수 전에? 파일 오픈 전에? 답은 wofstream의 인스턴스가 생성되기 전이다. (이거 떄문에 시간을 얼마나 소비했는지…) 아래는 이를 증명하는 코드이다.

   

   

코드에 적혀있는데로 wofstream은 인스턴스가 생성될 때 locale이 설정된다. 이 설정된 locale은 이후에 locale이 변경되어도 생성된 wofstream에 그대로 유지된다. 아마도 스트림별 다양한 locale을 지원하기 위해 이렇게 했나 싶다. 뭐.. 이것도 생각해보면 당연하지만…

코드는 locale 설정 전에 메모리에 할당된 스트림과 설정 후에 메모리에 할당된 스트림을 사용하여 파일에 한글 출력을 테스트한다. 위 코드를 컴파일 후 실행해보면 아래와 같이 locale 설정 전에 할당된 wofstream은 0kb로 한글을 출력하지 못한다.

   

   

이렇게 해결 방법을 알아도 문제가 되는 경우가 있는데 전역 변수(정적 변수)의 경우 locale 설정보다 먼저 메모리에 할당될 수 있다. 어쨌든 문제는 해결했으니 … bye!

   

이번 포스트 요약

wofstream은 기본 설정 사용시 wchar_t 형태의 파일 출력을 보장하지 않는다.

wofstream 인스턴스 생성 전, 즉 메모리에 할당되기 전에 locale 설정을 해야한다.

   

코드

int _tmain(int argc, _TCHAR* argv[])

{

/*

wofstream은 메모리에 할당될 때 locale이 설정된다.

이 설정된 locale은 이후에 locale이 변경되어도 유지된다.

*/

std::wofstream fstream_locale_before;

std::locale::global(std::locale("Korean"));

std::wofstream fstream_locale_after;

   

fstream_locale_before.open( _T("..\\test before locale setting.txt") );

fstream_locale_before << _T("한글 파일 출력 테스트") << std::endl;

fstream_locale_before.close();

   

fstream_locale_after.open( _T("..\\test after locale setting.txt") );

fstream_locale_after << _T("한글 파일 출력 테스트") << std::endl;

fstream_locale_after.close();

   

return 0;

}

   

'프로그래밍' 카테고리의 다른 글

Rstudio 3.3.0 스케일링 문제  (0) 2016.05.06
드라이버 개발 삽질 #1  (0) 2015.03.12
ifstream 64  (0) 2014.09.25
CPP 벡터 반복문 중 원소 지우기  (0) 2014.09.22
가상 함수 테스트  (0) 2014.07.05

ifstream 64

프로그래밍2014. 9. 25. 02:40

2년 전 쯤에 대용량 파일(2GB 이상의 파일) 처리가 가능한 프로그램을 만들어야 했다. 32비트 시스템에서는 4바이트 크기의 파일 포인터를 사용하기에 이런 파일에 대해 입출력 작업을 할 때 윈도우 API를 제외한 일반적인 방법으로 처리하기가 힘들었다. 지금이야 윈도우 API의 강력함을 알고 있지만서도 그 때 당시 크로스컴파일에 심취해있었기 때문에 윈도우 API로 파일 처리하는 것은 내 자존심이 허락하지 않았다.

직접 알아본 파일 처리 방법은 64비트 환경에서 컴파일 그리고 _fseeki64 류의 함수를 사용, fstream을 8바이트 파일 포인터를 지원하게 일반화 프로그래밍을 하는 것이었다. 급한데로 _fseeki64 류의 함수를 사용하여 잘 처리하였지만 코딩에 미련이 안남을 수 있겠는가? 시간이 남을 때 64비트 파일 포인터를 지원하는 fstream을 만드는 방법을 찾아보았다. 아래는 fstream64를 지원하는 코드이다.

   

#ifdef WIN32

typedef int64_t streamoff64;

class streampos64
{
        typedef streampos64 _Myt;
        typedef _Mbstatet _Statetype;
public:
        streampos64(streamoff64 _Off = 0)
                : _Myoff(_Off), _Fpos(0), _Mystate(0)
                {        // construct with stream offset
                }

streampos64(_Statetype _State, fpos_t _Fileposition)
                : _Myoff(0), _Fpos(_Fileposition), _Mystate(_State)
                {        // construct with conversion state and C file position
                }

_Statetype state() const
                {        // return conversion state
                return (_Mystate);
                }

   

직접 코드를 가져다 사용하면 C4927 에러가 나는데… 이게 여간 신경 쓰이는게 아니다.

   

c:\program files (x86)\microsoft visual studio 10.0\vc\include\streambuf(424): warning C4927: illegal conversion; more than one user-defined conversion has been implicitly applied

1> while calling the constructor 'streampos64::streampos64(streamoff64)'

1> c:\~\streamutil.h(15) : see declaration of 'streampos64::streampos64'

1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\streambuf(423) : while compiling class template member function 'streampos64 std::basic_streambuf<_Elem,_Traits>::seekoff(unsigned __int64,std::ios_base::seekdir,std::ios_base::openmode)'

1> with

1> [

1> _Elem=char,

1> _Traits=char_traits64<char>

1> ]

1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\fstream(135) : see reference to class template instantiation 'std::basic_streambuf<_Elem,_Traits>' being compiled

1> with

1> [

1> _Elem=char,

1> _Traits=char_traits64<char>

1> ]

1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\fstream(889) : see reference to class template instantiation 'std::basic_filebuf<_Elem,_Traits>' being compiled

1> with

1> [

1> _Elem=char,

1> _Traits=char_traits64<char>

1> ]

1> c:\~~~~~\header.h(63) : see reference to class template instantiation 'std::basic_ifstream<_Elem,_Traits>' being compiled

(생략)

   

C4927 에러는 warning 1단계 에러로 무진장 잘나온다. 한국어 버전은 어떻게 나오는지 모르겠지만 해석해보면 네가 정의한 데이터에 대해 암묵적으로 데이터 변환이 일어났는데 이를 해결 안하면 어떤 문제가 생길 수도 있다는 것이다. 이걸 한번 해결해보는게 바로 이번 포스트의 내용이다.

CPP에서 템플릿을 사용하는 함수나 클래스는 컴파일 시간에 그 타입이 결정된다. VC는 이에 대한 로그를 스택 형식으로 보여주기 때문에 관련 로그를 살펴보기 위해서는 맨 아래부터 살펴보면 아래 15번째 줄의 코드 라인부터 컴파일이 일어났고 이에 대한 워닝이 떴다는 것을 알 수 있다.

   

   

다음은 basic_ifstream에서 발생하는데 typedef basic_filebuf<_Elem, _Traits> _Myfb에서 워닝이 발생한다. 내용은 _Filebuffer를 만드는데 여기서 워닝이 발생한다~ 그리고 이 변수는 basic_filebuf에 속해있다 이다.

   

   

   

이제 실제 워닝 발생 지점이다.

   

   

ifstream64은 다음과 같이 아래의 소스 코드에 나와있듯이 basic_ifstream에 출력 문자열의 형태와 관리 방법을 정의하는 객체인 _Traits를 새롭게 정의한다. 여기서 주목해야될 것은 바로 pos_type과 off_type이다.

   

template<typename Elem>

class char_traits64 : public std::char_traits<Elem>

{

public:

typedef Elem char_type;

typedef long int_type;

typedef streampos64 pos_type;

typedef streamoff64 off_type;

typedef _Mbstatet state_type;

};

   

typedef std::basic_ifstream<char, char_traits64<char> > ifstream64;

   

일반적으로 ifstream에서 사용되는 char_traits는 아래와 같이 streampos와 streamoff 를 사용한다. 여기서 사용되는 streampos는 fpos<_Mbstatet>이며 streamoff는 32비트 정수형이다. ( * 64비트 환경에서는 64비트 정수형이다. )

   

   

소스코드에서 streamoff64는 uint64_t로 64비트 정수형이다. streampos64는 fpos<_Mbstatet>를 64비트에 맞춰서 새롭게 정의를 했다. 워닝은 바로 이 부분에서 발생하는 것이다. streampos64를 다시 살펴보면 생성자 부분에서 워닝이 발생한다는 것을 알 수 있다. 그렇다면 생성자에서 왜 워닝이 발생하는건가?

   

   

seekoff 함수의 return 문을 보면 streampos(~)를 반환한다. 하지만 return 데이터 형식은 pos_type으로 컴파일시에는 streampos64로 결정된다. 바로 여기에서 컴파일러는 데이터 형식이 정수형으로 비슷하지만 클래스에서 어떻게 처리할지 모르기 때문에 암묵적으로 데이터 변환이 일어나고 있다고 말해주는 것이다.

   

   

이를 해결하는 방법은 streampos에 해당하는 새로운 생성자를 만들어주면 워닝이 금방 해결 된다.

   

public:

streampos64(streamoff64 _Off = 0)

: _Myoff(_Off), _Fpos(0), _Mystate(0)

{        // construct with stream offset

}

   

streampos64(std::streampos _Off)

: _Myoff(_Off), _Fpos(0), _Mystate(0)

{        // construct with stream offset

}

   

fstream64를 사용하면서 선언한 곳마다 warning이 20~30줄 떠버리면 무진장 신경쓰인다. 거기다 왠지 모르게 C4927 워닝은 무시도 안된다. 이상 마친다~

   

그런데 64비트 환경에서 32비트로 컴파일하면 파일 포인터는 32비트일까 64비트일까? -_-??? 흠..

   

ps. boost::filesystem::fstream 도 있네? 봐봐야겠다.

일반적으로 벡터의 원소를 지울 때 erase를 사용하는데 이게 for 문을 돌리면서(iterator++를 하면서) 조건에 맞을 때 삭제하는 코드를 짜면 erase 후 iterator 변수가 가볍게 크래쉬를 발생시켜주신다. 할당해제하고 나면 어떻게 되는지 VS 환경에서 디버거로 본적이 있는데 iterator 변수가 할당해제한 원소를 계속 가리키고 있었던 것으로 기억난다. 아무튼 깔끔하게 프로그래밍 할려면 아래처럼...


std::vector<int *> vIntegers;

// fill integers in the vector.

for(int i = 0; i < 100; i++) {

vIntegers.push_back(new int(i));

}


auto it = begin(vIntegers);

while(it != end(vIntegers)) {

if(**it % 2 == 0) {

printf("%d ", **it);

it++;

} else {

// delete allocated memory of 4bytes, integer size

delete *it;

// erase returns next iterator of removed iterator 

it = vIntegers.erase(it);

}

}


아니면 삭제하는 부분을 그대로 for 문으로 나둬도 괜찮다.

for(auto it = begin(vIntegers); it != end(vIntegers);) {

while(it != end(vIntegers)) {

if(**it % 2 == 0) {

printf("%d ", **it);

it++;

} else {

// delete allocated memory of 4bytes, integer size

delete *it;

// erase returns next iterator of removed iterator 

it = vIntegers.erase(it);

}

}

}


for 문이 내게는 한 줄에 많은 정보를 줘서 더 가독성이 있다.

'프로그래밍' 카테고리의 다른 글

드라이버 개발 삽질 #1  (0) 2015.03.12
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
가상 함수 테스트  (0) 2014.07.05
최상위 윈도우 핸들로부터 모든 자식 윈도우 핸들 얻기  (0) 2014.03.27

class TestParent {
public:
	virtual void foo(void) {
		printf("call TestParent::foo()\n");
	}
	virtual void bar(void) {
		printf("call TestParent::bar()\n");
	}

public:
	int m_nMember1;
};

class TestChild1 
	: public TestParent {
public:
	void foo(void) {
		printf("call TestChild1::foo()\n");
	}

	int m_nMember2;
};

class TestChild2 
	: public TestParent {
public:
	void foo(void) {
		printf("call TestChild2::foo()\n");
	}

	int m_nMember2;
};

class TestChild3 
	: public TestParent {
public:
	void foo(void) {
		printf("call TestChild3::foo()\n");
	}

	int m_nMember2;
};

int main() {
	std::vector vTestCls;

	vTestCls.push_back(new TestParent);
	vTestCls.push_back(new TestChild1);
	vTestCls.push_back(new TestChild2);
	vTestCls.push_back(new TestChild3);

	for(auto p = begin(vTestCls); p != end(vTestCls); p++) {
		TestParent* pTestParent = *p;
		pTestParent->foo();
		pTestParent->bar();
	}
	
	void (TestParent::*pfn_parent_foo)(void);
	void (TestChild1::*pfn_child1_foo)(void);
	void (TestChild2::*pfn_child2_foo)(void);
	void (TestChild2::*pfn_child3_foo)(void);

	TestChild1* pTestChild1 = new TestChild1;
	pfn_child1_foo = &TestChild1::foo;

	for(auto p = begin(vTestCls); p != end(vTestCls); p++) {
		pfn_parent_foo = &TestParent::foo; 
		// 함수의 호출 주소만 가짐(인스턴스 X)
		TestParent* pTestParent = *p;

		pTestParent->m_nMember1 = 0x41414141;
		(pTestParent->*pfn_parent_foo)(); 
		// 인스턴스에서 함수의 주소를 이용하여 해당 함수를 호출
		// 결국 vtable을 또 거치네

		pTestParent->bar();
	}

	return 0;
}

MFC만 하다보니까 WinAPI는 너무 약한거 같다...

기본이 되는 힘을 익혀야되는데

아래 함수는 프로세스 자신 뿐만 아니라

타프로세스의 윈도우 핸들을 받을 경우 그에 속하는 모든 자식 윈도우 핸들을 출력해주는 함수이다. 

void ChildWindows(HWND parentHwnd) {
    HWND childHwnd;
    childHwnd = GetWindow(parentHwnd, GW_CHILD);
    
    while(childHwnd) {
        printf("%#08x\n", childHwnd);
        ChildWindows(childHwnd);
        childHwnd = GetNextWindow(childHwnd, GW_HWNDNEXT);
    }

    return;
}

 

'프로그래밍' 카테고리의 다른 글

드라이버 개발 삽질 #1  (0) 2015.03.12
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
CPP 벡터 반복문 중 원소 지우기  (0) 2014.09.22
가상 함수 테스트  (0) 2014.07.05