원본글 : http://www.devpia.com/forum/BoardView.aspx?no=7286&ref=7286&page=1&forumname=vc_lec&stype=

Windows XP에서 Fast User Switching을 지원하는 응용 프로그램 만들기

1. 개요


Windows XP부터는 Fast User Switching 기능이 도입되었습니다. 여기서는, 응용 프로그램 작성시, Fast User Switching이 일어날 때 개발자가 이 기능을 바르게 지원하기 위해서 필요한 것들에 대해서 알아보도록 하겠습니다.

2. Fast User Switching 지원을 위해서 응용 프로그램에서 해야 할 일 - 1

당연한 이야기이지만, Fast User Switching의 지원을 하기 위해서는, 우선 WindowsXP의 세션 상태의 변화를 응용 프로그램에서 감지 할 수 있어야 합니다.

WindowsXP는 세션의 상태가 변할 때 마다, WM_WTSSESSION_CHANGE 메세지를 특정한 윈도우들에게 보내줍니다. 이 메세지를 받기 위해서는 WTSRegisterSessionNoticiation 함수를 호출해야 합니다. 

컴파일시 대상 운영체제를 WindowsXP로 설정합니다.
#define _WIN32_WINNT 0x0501

#include <wtsapi32.h>
#pragma comment( lib , "Wtsapi32.lib")

윈도우를 생성한 다음 아래의 함수를 호출합니다.
WTSRegisterSessionNotification( hWnd , NOTIFY_FOR_THIS_SESSION );


이렇게 해서, 등록에 성공하면 WindowsXP는 WM_WTSSESSION_CHANGE 메세지를 보내 주면서, WPARAM의 값으로 세션의 변화를 알려 줍니다.

case WM_WTSSESSION_CHANGE:
switch( wParam )
{
case WTS_CONSOLE_CONNECT:
  ...
  break;
case WTS_CONSOLE_DISCONNECT:
  ...
  break;
case WTS_SESSION_LOCK:
    ...
  break;
case WTS_SESSION_UNLOCK:
    ...
  break;
default:
break;
}
break;



사용자 전환이 발생할 경우, WTS_SESSION_LOCK, WTS_CONSOLE_DISCONNECT, WTS_SESSION_UNLOCK, WTS_CONSOLE_CONNECT의 메세지가 차례로 발생합니다.

이렇게 해서, 세션의 변화 상태를 관찰할 수 있으면, 개발자는 그에 맞게 응용 프로그램의 행동을 결정해 주는 것이 필요합니다.

예를 들어서, 오디오 장치의 경우, 끓어진 세션에 있는 오디어 플레이어가 음악을 재생하고 있고, 새롭게 로그인 한 사용자가 이 오디오 장치를 이용하여, 넷미팅 같은 소프트웨어를 이용해서 원격 회의를 하려고 하는 경우, 원격 회의가 제대로 진행되기 어려울 수도 있습니다.

극단적인 예를 들었지만, 개발자가 세션이 변함에 따라서, 응용 프로그램의 행동을 미리 정의해 놓는 것은 반드시 필요합니다.

3. Fast User Switching 시 응용 프로그램에서 해야 할 일 -2

이러한 Fast User Switching을 잘 지원하기 위해서, 개발자는 아래의 것들을 응용 프로그램 개발시 고려해야 합니다.

인스턴스 관리

개발자가 응용 프로그램의 인스턴스가 단 하나만 동작하기를 원하는 경우, 아래의 경우를 고려해야 합니다.

FindWindow 혹은 FindWindowEx를 이용해서 응용 프로그램의 인스턴스를 찾는 경우, 다른 세션에 있는 이 함수들이 다른 세션에 있는 응용 프로그램의 인스턴스까지 찾을 수 없습니다.

뮤텍스 혹은 세마포어 같은 커널 오브젝트를 이용하여 인스턴스를 생성을 확인하는 경우, 이 객체들의 이름 앞에 '\Global\'이라는 접두사를 붙여서, 전역 객체로 선언해야 합니다. 각 세션은 세션 마다 커널 객체들의 네임스페이스가 존재하고, 위의 '\Global\'을 붙이지 않는 객체는 각 세션의 로컬 커널 객체로 선언되어, 다른 세션에 있는 동일한 이름의 뮤텍스 혹은 세마포어를 인식하지 못합니다. 예를 들어 "\Global\MutexTest" 이런 식으로 커널 객체의 이름을 명명해 주어야 합니다.

결국 단 하나만의 인스턴스가 동작하기를 원하는 경우, 전역 뮤텍스 혹은 세마포어을 생성해서, 기존에 이 커널 객체들이 생성이 되었는지의 여부를 이용하여 인스턴스를 생성을 제어해야 합니다.


사용자에 따른 데이타 분리

Windows XP의 이러한 기능 때문에 단일 프로그램을 여러 명의 사용자가 동시에 사용할 수 있고, 이 때문에 응용 프로그램은 사용자 별로 데이타를 저장하는 것이 필요합니다. 이 때 마이크로 소프트는 각 사용자 별로 생성되는 데이타는 각 사용자의 My Document 폴더 밑에 저장하는 것을 권장하고 있습니다. 이 My Document 폴더는 SHGetFolderPath에서 CSIDL_PERSONAL을 인자로 넘겨주어 알 수 있습니다.

마이크로 소프트에서 권장하는 디렉토리들을 좀 더 몇 개만 더 나열하면:

CSIDL_MYPICTURES: 이미지 파일을 저장시에 사용하기를 권장합니다. 각각의 개인마다 다르게 생성됩니다.

CSIDL_COMMON_APPDATA: 개인 데이타가 아닌 응용 프로그램의 데이타를 저장할 때 사용하기를 권장합니다. 기본 패스는 C:\Documents and Settings\All Users\Application Data 입니다.

CSIDL_LOCAL_APPDATA: 임시 파일등을 저장하기 위해서 사용됩니다.

레지스트리 저장소의 분리

위의 사용자별 데이타 저장과 연결되는 이야기로서, 사용자들의 데이타를 레지스트리에 저장할 필요가 있을 경우, HKCU (Current User)를 사용하시고, HKLM (Local Machine)을 사용하지 말라고 권장하고 있습니다.

4. 프로그램 종료시 할 일

WTSRegisterSessionNotification에서 등록한 윈도우를 Destroy하기 이전에, WTSUnRegisterSessionNotification을 호출해 주시기 바랍니다.

5. 결론

결국 Fast User Switching을 지원하기 위해서는 세션의 변화를 감지해야 하고, 데이타를 각각의 개인별로 분리하며, 전역으로 쓰는 자원에 대해서는 세션의 변화에 따라 어떤 식으로 활용해야 하는 지를 미리 정의해 놓아야 합니다.

6. 참고

http://support.microsoft.com/default.aspx?scid=kb%3Bko%3B310153
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwxp/html/winxpfus.asp

'게임개발 > ' 카테고리의 다른 글

synchronized block in C++  (0) 2006.05.03
최상위 비트 인덱스 가져오기  (0) 2006.05.02
시스템 이미지 가져다 쓰기  (1) 2006.03.06
VS2005 실행모듈 배포하기  (1) 2006.02.14
다른 프로그램창 Top으로 올리기  (0) 2006.01.24

에에..시스템 이미지란..
내컴퓨터나 휴지통, 폴더 아이콘등 윈도우의 기본적인 이미지를 말한다.

에에... 대략 이런 프로그램을 만들때 필요하다.


왼쪽에 있는 폴더 창과 오른쪽의 파일리스트 창과는 살짝 차이가 있다.

일단 왼쪽의 폴더 창에서는
폴더의 열린 모양과 닫힌 모양이 필요하다

m_ImageList.Create( 16, 16, ILC_COLOR32, 0, 0 );
rTree.SetImageList( &m_ImageList, LVSIL_NORMAL );

TCHAR szTemp[MAX_PATH];
GetSystemDirectory( szTemp, MAX_PATH );

_tcscat_s( szTemp, MAX_PATH, _T( "\\Shell32.dll" ) );

HICON hIconSmall;
ExtractIconEx( szTemp, 3, NULL, &hIconSmall, 1 );
m_ImageList.Add( hIconSmall );

ExtractIconEx( szTemp, 4, NULL, &hIconSmall, 1 );
m_ImageList.Add( hIconSmall );


이런식으로 Shell32.dll의 이미지를 뽑아다 쓴다.
이미지 리스트를 Create할때 ILC_COLOR32가 아닌걸로 하면 알파가 제대로 안빠지므로 주의!

위에 보면 ExtractIconEx에 두번째 인자가 이미지 번호다
다른 번호를 넣으면 다양한 아이콘들을 가져다 쓸 수 있다.

그리고 오른쪽 파일창같은 경우는 이것과는 다른데
파일 확장자별로 연결되어 있는 아이콘을 가져다 써야 한다.
처음에 대략

HIMAGELIST hSystemImgListSmall, hSystemImgListLarge;
Shell_GetImageLists( &hSystemImgListLarge, &hSystemImgListSmall );
m_ImageListSmall.Attach( hSystemImgListSmall );
m_ImageListLarge.Attach( hSystemImgListLarge );

rListCtrl.SetImageList( &m_ImageListSmall, LVSIL_SMALL );
rListCtrl.SetImageList( &m_ImageListLarge, LVSIL_NORMAL );
이런식으로 해준뒤에

SHFILEINFO sfi;
SHGetFileInfo( rFilename.c_str(), 0, &sfi, sizeof(SHFILEINFO), SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_TYPENAME );
하면 sfi.iIcon이 가져온 이미지 리스트의 아이콘 인덱스가 되겠다.

여기서 대략난감했던 부분이 파일리스트에서도 폴더 아이콘이 필요하다는 거였는데.

SHFILEINFO sfi;
SHGetFileInfo( (LPCTSTR)"Does not matter", FILE_ATTRIBUTE_DIRECTORY, &sfi, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES);
대략 이런식으로 가져올 수 있다.
혹시나 폴더 열린 아이콘이 필요하다면(아마 필요없겠지만) 알아서 이미지리스트를 합쳐서 쓰삼-_-;

devpia에 내용을 다 충족하는 내용들이 없어서 여기저기 뒤지고 삽질하고 고생했다.

참고로 vs2005에서는 (2003도 되는거 같다.)
처음에 MFC어플리케이션 만들때 익스플로러 스타일~ 을 체크해주면 위에처럼 알아서 스플리트 윈도우로 왼쪽엔 트리뷰 오른쪽엔 리트스컨트롤뷰로 붙여주니까 쓸데없는 삽질은 하지 말쟈-_-;

그나저나 오랜만에 어플리케이션 프로그래밍을 하자니 재밌다
에...만들고 있는 프로그램의 용도는 리소스 팩 파일 관리프로그램이다.
머 재밌기는 하지만 패치 프로그램을 만들어야 해서 Drag&Drop까지만 하고 치울 생각이다.
어플리케이션 내로 Drag는 메세지 핸들링만 해주면 되니까 쉬운데 밖으로 빼는건 꽤 난이도가 있을듯.

2005의 crt dll은 그냥 배포하면 남에 컴퓨터에서 실행이 안되는 지랄맞은 내용으로 바꼈다-_-
WinSxS라고 해서 옆에옆에 무슨 어셈블리라고 하는데 자세한 내용은 아래의 김성민씨의 사이트 참고
http://www.serious-code.net/moin.cgi/RedistributingVisualCppRunTimeLibrary

나도 이거때문에 많이 고생했는데
beta2때는 직접 폴더 뒤져서 시행착오해서 필요한 파일들 추출해서 자동압축풀림-_-으로 해서 배포했고
rtm이 되더니 C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\vcredist_x86 폴더안에
인스톨본이 생겼다
인스톨쉴드를 써서 머지해도 되지만 툴을 인스톨 하지는 않으므로 걍 실행하라고 배포했다-_-

그리고 정식판이 되더니
C:\Program Files\Microsoft Visual Studio 8\VC\redist
폴더안에 crt dll들이 차곡차곡 정리되어 있다
분명 rtm에선 못본 기억인데-_-
한글판 msdn을 찾아보니 windows안에 winsxs폴더를 뒤지고 없으면 crt명과 같은 폴더명이 있으면 그안에 manifest파일을 뒤지고 거기도 없으면 실행파일과 같은 폴더에서 manifest를 뒤진다..라고 한다.

그래서 폴더째로 배포하면 그나마 깔끔하겠다...라는 생각을 하고..
옆에 데스크탑을 xp를 깔아보고 2000을 깔아보고 하면서 테스트를 해봤는데
winsxs폴더를 뒤지거나 같은 폴더명안을 뒤지는건 xp이상에서고 그 이하에선 안된다
xp이하에서는 manifest참고 안하고 같은 폴더나 system32에서 직접 dll을 찾는다. ( 이것도 msdn에 써있는 내용이다 )
결국 실행파일과 같은 폴더에 넣었다-_-

MFC를 안쓰고 release버전만 배포한다면
C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT
안에 있는
Microsoft.VC80.CRT.manifest
msvcp80.dll
msvcr80.dll
만 실행파일과 같은 폴더에 넣어주면 된다.
msvcm80.dll은 매니지드C++용 crt라 native를 쓰는 경우는 배포하지 않아도 된다.

윈도우를 Top으로 올리는건

SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
로 하면 되긴하지만, 이건 같은 어플리케이션내의 윈도우만 가능하다.


다른 어플리케이션의 윈도우는 이렇게 한다.

void ForceSetTop(HWND hWnd)
{
DWORD fromId = GetCurrentThreadId();
DWORD toId = GetWindowThreadProcessId(GetForegroundWindow(), NULL);

AttachThreadInput(fromId, toId, TRUE);
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
AttachThreadInput(fromId, toId, FALSE);
}


'게임개발 > ' 카테고리의 다른 글

시스템 이미지 가져다 쓰기  (1) 2006.03.06
VS2005 실행모듈 배포하기  (1) 2006.02.14
Variadic Macros in VC2005  (0) 2006.01.23
Named Return Value Optimization in Visual C++ 2005  (0) 2006.01.04
VC2005 추가 키워드  (2) 2006.01.04

전에 써논줄 알았는데 없네

VC2005에서는 이런게 가능하다.
#define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }

#define 에서 argument list를 지원하지 않아서 불편했었는데 ㅋ

#ifdef __USE_TRACE__
#define STRACE( ... ) g_STrace.Printf( __VA_ARGS__ );
#else
#define STRACE( ... )
#endif

이런식으로 쓰고 있다

다른 용도는 잘-_-;;

'게임개발 > ' 카테고리의 다른 글

VS2005 실행모듈 배포하기  (1) 2006.02.14
다른 프로그램창 Top으로 올리기  (0) 2006.01.24
Named Return Value Optimization in Visual C++ 2005  (0) 2006.01.04
VC2005 추가 키워드  (2) 2006.01.04
D3DXLoadSurfaceFromSurface  (0) 2005.12.27

'게임개발 > ' 카테고리의 다른 글

다른 프로그램창 Top으로 올리기  (0) 2006.01.24
Variadic Macros in VC2005  (0) 2006.01.23
VC2005 추가 키워드  (2) 2006.01.04
D3DXLoadSurfaceFromSurface  (0) 2005.12.27
mutable  (0) 2005.11.22

아마도 표준은 아닐거라고 생각하고 2003의 지원여부는 잘 모름-ㅅ-;
이미 표준이 아니어도 vc2005의 강력한 기능이 너무나도 유용한 경우는 생까주기로 하셨슴.

override

abstract

__interface

sealed

.끝.
native 기준이고 clr에서만 사용가능한건 적지 않았음
위에 몇 개 나왔지만 __is_abstract같은 컴파일 타임에 사용가능한 TypeTraits가 꽤 있다.
특정 클래스가 base클래스를 상속받았는지를 체크하는것도 있고(clr에서만 되지만)
__has_copy(type)나 __has_assign(type)같은
native에서 쓸만한것도 꽤 있다.
근데 사실 TypeTraits는 필요한건 native지원안하면 loki를 써버리면 그만이라 헹~

'게임개발 > ' 카테고리의 다른 글

Variadic Macros in VC2005  (0) 2006.01.23
Named Return Value Optimization in Visual C++ 2005  (0) 2006.01.04
D3DXLoadSurfaceFromSurface  (0) 2005.12.27
mutable  (0) 2005.11.22
콤보박스 드롭박스 부분 크기 조절하기  (0) 2005.11.22

D3DXLoadSurfaceFromSurface

이게 있었다는 걸 분명히 알고 있었는데 까먹고 있었다-.ㅜ

왜 여태 메모리에 저장했다 다시 로드했지-ㅅ-


'게임개발 > ' 카테고리의 다른 글

Named Return Value Optimization in Visual C++ 2005  (0) 2006.01.04
VC2005 추가 키워드  (2) 2006.01.04
mutable  (0) 2005.11.22
콤보박스 드롭박스 부분 크기 조절하기  (0) 2005.11.22
vs 2005의 for each  (0) 2005.11.07

This keyword can only be applied to non-static and non-const data members of a class. If a data member is declared mutable, then it is legal to assign a value to this data member from a const member function.

라고 msdn에 나와있다.
const 멤버함수에서 수정할 수 있단다.
보고나니 아...이거였지...라는 생각이 난다-_-;

크리티컬섹션거는거때매 const를 붙이지 못해서 불만을 뿜어내고 있었는데..
흠흠..

이런 변수 키워드들에 대해 한번 찾아봐야지..하고 계속 미루고 있었는데
이 게으름증이란..헹~

ps. volatile은 내용은 대충 알것도 같은데 어떤 상황에 써야할지는 잘 모르겠다-.ㅜ

'게임개발 > ' 카테고리의 다른 글

VC2005 추가 키워드  (2) 2006.01.04
D3DXLoadSurfaceFromSurface  (0) 2005.12.27
콤보박스 드롭박스 부분 크기 조절하기  (0) 2005.11.22
vs 2005의 for each  (0) 2005.11.07
VS에서 lua의 syntax coloring을 해보쟈  (0) 2005.10.14

사실 원래는 적당한 크기로 잡혀져서 조절할 일이 별로 없었는데.
멀 삽질했는지 한줄씩 밖에 안나와서 상당히 난감한 상황이었다-_-;
잡설은 집어치우고..

콤보박스를 선택하면 상하크기조절은 Disable된 상태인데..
콤보박스의 화살표(얘를 머라그러나-_-) 부분을 눌러주면
드롭박스 부분의 크기를 설정할 수 있다.

허접함을 뛰어넘어 검색도 한번 안해본 이 게으른 담당 프로그래머 때문에 몇주간 툴을 불편하게 사용하신 그래픽팀 일동에게 심심한 사죄의 말씀을-_-;

'게임개발 > ' 카테고리의 다른 글

D3DXLoadSurfaceFromSurface  (0) 2005.12.27
mutable  (0) 2005.11.22
vs 2005의 for each  (0) 2005.11.07
VS에서 lua의 syntax coloring을 해보쟈  (0) 2005.10.14
파일포맷 png  (0) 2005.09.07

+ Recent posts