Windows Vista와 Windows 7의 Version checking

Windows Vista나 Windows 7에서 어플리케이션을 수행해 보면 프로그램이 정상적으로 수행되지 않고 조용히 실패(silent fail)해 버리거나 “윈도우 XP 이상의 운영체제에서만 수행될 수 있습니다.”와 같은 오류 메시지가 나타나는 경우가 있다. 이러한 문제의 대부분은 어플리케이션 내부에서 운영체제의 버전을 확인하는 루틴에서 문제가 있는 경우이다. 어플리케이션이 이와 같이 버전 정보 확인에 실패하는 이유는 크게 2가지로 나누어 볼 수 있다.

  • 버전 확인 코드의 결함(버그). 주 버전(major version)이 증가했음에도 부 버전(minor version)이 감소하였다는 이유로 실패한다거나(예. 버전이 5.1에서 6.0으로 변경되는 것과 같이) 최신의 운영체제가 설치되어 있음에도 이전 운영체제의 서비스 팩 설치 여부를 확인하는 경우(예. Windows XP SP2에서 Windows Viats SP1으로 버전이 변경된 경우)
  • 개발자가 테스트 해 보지 않은 운영체제에서 어플리케이션이 수행되지 않도록 의도적으로 제한한 경우(미래에 출시될 운영체제를 위해서라도 이처럼 어플리케이션의 수행을 제한해서는 안 된다.)

잘못된 버전 확인 코드로 인해 실제로는 호환되지 않는 운영체제에서 어플리케이션이 수행되면 보통의 경우 오류 메시지가 출력되고 이를 통해 그 원인을 추적할 수 있지만, 간혹 앞서 말한 바와 같이 아무런 동작도 수행되지 않고 프로세스가 조용이 종료 되어버리는 경우도 있다.

다음 절에서 버전 확인 과정에서 야기될 수 있는 호환성 문제를 피할 수 있는 방법과 운영체제의 버전을 확인하는 올바른 방법에 대해서 설명하고 최종적으로 운영체제의 버전을 확인하기 보다는 운영체제의 기능이 사용 가능한지를 확인하는 더 나은 대안을 제안할 것이다.

문제상황을 해결하는 방법

Windows Viata와 Windows 7는 버전 확인 과정에서 발생할 수 있는 문제 상황을 회피할 수 있는 두 가지 메커니즘을 제공하고 있다.

1. 호환성 모드(Compatibility Mode) : 호환성 모드는 일반 사용자가 호환성 문제를 쉽게 해결할 수 있도록 제공되는 방법으로, 이전 버전의 윈도우에서만 수행되도록 작성된 어플리케이션을 Windows Vista나 Windows 7에서 수행될 수 있도록 운영체제의 version을 반환하는 함수들이 이전 운영체제의 version 정보를 반환하도록 버전 속이기(Version lie)를 수행하도록 하는 방법이다. 프로그램의 속성(Properties) 에서 호환성(Compatibility) 탭을 통해서 운영체제 버전 속이기를 수행할 수 있다.

2. 어플리케이션 호환성 툴킷(ACT: Application Compatibility Toolkit) : IT 프로와 개발자들이 어플리케이션 호환성 문제를 확인할 수 있도록 다양한 도구를 포함하고 있는 툴킷이다. 이를 이용하면 다양한 호환성 문제를 확인할 수 있으며, 개발자가 “버전 속이기(Version lie)등과 같은 방법을 통해서 손쉽게 문제 상황을 회피할 수 있는 방법을 제공해 준다.

호환성 모드(Compatibility Mode)

호환성 모드는 다음과 같이 사용할 수 있다.

1. 실행파일이나, 바로가기에서 오른 마우스를 클릭한다.
2. 속성(Properties)를 클릭한다.
3. 호환성(Compatibility) 탭을 클릭한다.
4. 이 프로그램을 실행할 호환 모드(Run this program in compatibility mode for)에서 어플리케이션이 수행 가능할 것으로 예상되는 운영체제 버전을 선택한다. 어플리케이션 여러 개의 실행파일로 구성되어 있는 경우 각각의 실행파일에 대해서 개별적으로 이러한 작업을 수행해 주어야 한다.

image 

5. 확인(OK)를 눌러 대화창을 닫는다.

주의: 호환성 모드는 .net framework 기반의 managed code로 개발된 어플리케이션이 Environment.OSVersion을 사용하여 운영체제의 버전을 얻어오거나 P/Invoke를 사용하여 Win32 함수(예. GetVersionEx)를 호출하는 경우에는 영향을 미치지 못한다. 하지만 어플리케이션이 native code와 managed code가 섞여 있는 경우라면 적용 해 볼만하다. 다행히도 native code에서 버전 확인을 시도하는 경우라면 호환성 모드가 정상적으로 적용될 것이기 때문이다.

어플리케이션 호환성 툴킷(ACT: Application Compatibility Toolkit)

1. ACT를 설치한 후 시작 메뉴에서 Compatibility Administrator를 수행한다.
2. 왼쪽 트리에 “Custom Database” 노드가 나타나지 않는다면 툴바에서 “New”를 선택한다.

image

3. “New Database”를 오른 마우스 클릭한다.
4. “Rename”을 선택하고 호환성 database의 이름을 변경한다.
5. 변경한 database의 이름을 오른 마우스로 클릭한 후 “Create New”를 선택 후, “Applicatio Fix”를 클릭하면, 다음과 같이 “Create new Applicatio Fix” 대화창이 나타난다.

image

6. 세부 내용을 입력한다.
7. Next를 클릭한다.

image

8. Operating System Modes에서 None을 선택한다.
9. Select additional compatibility modes에서 “WinXPSP2VersionLie”를 선택한다.
10. Next를 클릭한다.

image

11. 어플리케이션에 추가적인 수정이 필요한 경우 각각을 선택한다.
12. Next를 클릭한다.

image

13. 윈도우가 버전 속이기(Version Lie)를 수행할 실행 파일을 구분할 수 있도록 여러가지 조건들을 선택한다.
14. Finish를 클릭한다.
15. 툴바에서 Save 버튼을 클릭하여 compatibility database를 저장한다(확장자는 .sdb 이다).
16. 윈도우는 상당히 많은 프로그램에 대한 다양한 수정사항들을 포함하고 있는 compatibility database와 함께 출시된다. Database/Application 노드를 확장해 보면 그러한 정보를 살펴볼 수 있으며, 하부 노드를 클릭하여 어떤 어플리케이션에 어떠한 수정 사항들이 적용되고 있는지도 살펴볼 수 있다.

더 좋은 버전 확인 방법

현재 운영 중인 운영체제가 특정 기능을 제공하는지의 여부를 확인하기 위해서 운영체제의 버전 정보를 확인하는 것은 그다지 좋은 방법은 아니다. 그럼에도 불구하고 운영체제가 제공하는 특정 기능의 가용 여부를 확인하는 방법이 운영체제의 버전 정보를 확인하는 방법 외에는 달리 대안이 없다면 다음에 설명할 내용을 주의 깊게 살펴보기 바란다.

native 어플리케이션의 경우, 항상 새로운 운영체제에서도 정상적으로 어플리케이션이 수행될 수 있도록 작성되어야 한다. 운영체제의 버전이 변경되었다 하더라도 비정상적으로 어플리케이션 동작해서는 안 된다. 아래에 Win32의 GetVersionEx 함수를 호출하는 사용 예를 나타내었다. 이 코드는 주버전(major version)이 5보다 큰지(Windows Viata, Windows Server 2008 R2, Windows 7) 혹은 주버전이 5이고 부버전(minor version)이 1 이상(Windows XP나 Windows Server 2003)인지를 확인한다.

C++

void main()
{
OSVERSIONINFO osvi;
BOOL bIsWindowsXPorLater;

ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

GetVersionEx(&osvi);

bIsWindowsXPorLater =
( (osvi.dwMajorVersion > 5) ||
( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));

if(bIsWindowsXPorLater)
printf("The system meets the requirements.\n");
else printf("The system does not meet the requirements.\n");
}

다음은 VerifyVersionInfo 함수를 사용하여 최소 운영체제의 버전을 확인하는 코드의 예이다.


C++

#include <windows.h>

BOOL Is_WinXP_SP2_or_Later ()
{
OSVERSIONINFOEX osvi;
DWORDLONG dwlConditionMask = 0;
int op=VER_GREATER_EQUAL;

// Initialize the OSVERSIONINFOEX structure.

ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = 5;
osvi.dwMinorVersion = 1;
osvi.wServicePackMajor = 2;
osvi.wServicePackMinor = 0;

// Initialize the condition mask.

VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );

// Perform the test.

return VerifyVersionInfo(
&osvi,
VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
dwlConditionMask);
}

.NET Framework 개발자라면 Environment.OSVersion.Version 속성 값을 Version 타입의 객체와 ==, !=, <=, <, >, >= 연산자를 이용하여 비교할 수 있다.


C#

// This code checks if the OS is at least Windows XP
if (Environment.OSVersion.Version < new Version(5, 1))
{
MessageBox.Show("Windows XP or later required.",
"Incompatible Operating System", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}

운영체제의 기능 확인

앞서 언급한 바와 같이 운영체제가 제공하는 기능의 가용여부를 확인하기 위해서 버전정보를 이용하는 것은 그다지 좋은 방법이 아니다. 왜냐하면 운영체제는 배포되는 DLL에 따라서 제공되는 기능이 가감될 수 있기 때문이다. 따라서 운영체제의 플랫폼과 버전 정보를 확인하는 함수인 GetVersionEx 함수를 사용하기 보다는 기능 자체가 지원되는지의 여부를 직접적으로 확인하는 것이 낫다. 예를 들어 Direct2D의 DirectWrite API와 Windows Vista에서 제공되는 Ribbon API를 사용할 계획이라고 하자. 설사 이러한 API를 사용하지 못하는 경우라 하더라도 어플리케이션 자체가 전혀 수행될 수 없다면 곤란하다.


비록 어플리케이션의 기능과 성능에 일부 제약이 있더라도 가능하다면 어플리케이션을 수행할 수 있도록 해주어야 할 것이다. Win32 개발자라면 이를 위해 다음과 같은 기법을 사용할 수 있다.


사용하려는 함수를 구현하고 있는 라이브러리가 어플리케이션의 가상 메모리 주소 공간에 로드되어 있지 않다면 LoadLibrary()를 사용하여 라이브러리를 로드하고, 앞서 로드되어 있는 경우라면(예 Kernel32.dll) GetModuleHandle() 함수를 이용하여 DLL의 핸들 값을 얻는다. 만일 LoadLibrary()나 GetModuleHandle() 함수가 NULL을 반환한다면 오류가 발생한 것이다.


GetProcAddress() 함수를 이용하여 함수 포인터를 획득한다. GetProcAddress()가 NULL을 반환하면 함수가 존재하지 않는 것이다. 만약 이 함수를 통해서 함수 포인터를 받아올 수 있다면 적절한 함수 원형을 가리키는 함수 포인터로 변환을 수행하면 된다. 그런데 몇몇 함수의 경우 함수 자체는 존재하지만, 함수 내부가 구현되지 않은 형태일 수도 있으며, 이 경우 구현되지 않음(not implemented) 오류가 발생할 수도 있으므로 이러한 오류도 반드시 확인해야 한다. 아래에 이러한 기법을 구현한 예를 나타내었다.


C++

// define function pointer type
typedef BOOL (WINAPI *SetWaitableTimerExProc)(
__in HANDLE hTimer,
__in const LARGE_INTEGER *lpDueTime,
__in LONG lPeriod,
__in PTIMERAPCROUTINE pfnCompletionRoutine,
__in LPVOID lpArgToCompletionRoutine,
__in PREASON_CONTEXT WakeContext,
__in ULONG TolerableDelay
);

LARGE_INTEGER liDueTime;
liDueTime.QuadPart = 0;
int period = 1000;
unsigned int tolerance = 1000;
HANDLE hTimer = // Get timer handle

REASON_CONTEXT reasonContext = {0};
reasonContext.Version = 0;
reasonContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
reasonContext.Reason.SimpleReasonString = L"MyTimer";

// Get module handle to a module which is already loaded
HMODULE hKernel32Module = GetModuleHandle(_T("kernel32.dll"));
if (hKernel32Module == NULL)
return FALSE;

// Get Address of function
SetWaitableTimerExProc pFnSetWaitableTimerEx =
(SetWaitableTimerExProc) ::GetProcAddress(hKernel32Module,
"SetWaitableTimerEx");

// Check if the function exists
if (pFnSetWaitableTimerEx == NULL)
return FALSE;

// Call function
if (!pFnSetWaitableTimerEx(hTimer, &liDueTime, period, NULL, NULL,
&reasonContext, tolerance)
{ /* handle error */ }

이와는 다른 방법으로 DLL 지연 로딩(delayed loading)을 이용한 후, __try…__except 블록 내에서 함수를 호출하는 방법을 사용할 수도 있다.(이에 대해서는 다음 링크를 확인하기 바란다. Linker Support for Delay-Loaded DLLs


만약 COM API를 사용하는 경우라면 CoCreateInstance와 QueryInterface함수의 반환 값에 대하여 오류 처리를 수행할 수 있으며, .NET framework 어플리케이션에서 P/Invoke를 이용하여 WIN32 API를 사용하는 경우라면 EntryPointNotFoundException과 DllNotFoundException에 대하여 예외 처리를 수행하면 된다.


참고



추가 자료


by 김명신 | 2009/09/23 10:02 | 복잡한컴퓨터이야기 | 트랙백 | 덧글(0)
Doloto를 아십니까?

Doloto는 Microsoft Research에서 MSDN DevLab을 통해서 공개한 tool로서 한마디로 말하자면 Download Optimizer 정도로 부를 수 있겠다. 이 툴을 이용하면 복잡한 AJAX web application의 초기 download 시간을 상당히 줄여줄 수 있다. 유일한 요구사항으로는 .Net framework 3.5 정도이다. 마이크로소프트는 Rich user experience를 제공하기 위해서 AJAX를 사용하게 되면 종종 초기에 download 해야 하는 코드의 양이 많아져서 초기 download 시간이 커지는 문제가 생기는데 이러한 문제를 Doloto가 상당부문 경감 시켜줄 수 있다고 한다.

다양한 종류의 AJAX application을 여러 network 환경에서 테스트 해본 결과 Doloto를 사용하면 Javascript에 대한 초기 download 양을 40%이상 줄일 수 있다고 하며, 네트워크의 속도에 따라 상이하긴 하겠지만 대략 30~40%정도 빠른 반응 속도를 보여준다고 한다. 아래 차트는 몇몇 사이트들에 대하여 doloto의 적용 전후의 결과를 나타낸 것이다.

Doloto download savings

Doloto는 과연 어떻게 동작하는 것일까? Doloto는 standalone client-sde tool이며 마이크로소프트 개발부의 부사장인 S.Somasegar는 다음과 같은 3가지 과정을 수행한다고 한다.

1. Doloto profiles your application. Doloto performs profiling by running a local proxy on your machine that intercepts JavaScript files and instruments them to capture timestamps at runtime for every JavaScript function in a browser-independent manner.

2. Profiling information is used to calculate code coverage and a clustering strategy. This determines which functions are stubbed out and which are not and groups functions into batches which are downloaded together, called clusters.

3. Doloto rewrites JavaScript code. It then saves it to disk so that you can upload it to the server. The entire process happens on your machine, without needing access to the server. This way, you can profile and optimize the JavaScript of a any third-party site without special access to their servers. When you are satisfied with Doloto’s results, you can deploy the rewritten files to the server.

Doloto는 다음 URL을 통해서 download 받을 수 있다. Doloto

좀 더 자세한 사항은 Microsoft Research, MSDN DevLabs의 Doloto forums을 확인하기 바란다. S.Somasegar’s가 작성한 doloto에 대한 글은 다음 URL에서 확인해 볼 수 있다. Somasegar's WebLog : Doloto on DevLabs

by 김명신 | 2009/09/11 15:04 | 트랙백 | 덧글(0)
저의 Twitter
제 주위의 twitter 하시는 분이 상당히 늘어서 저도 한번 참여 해볼까 합니다.

http://twitter.com/himskim

by 김명신 | 2009/07/13 10:50 | 살다보면 | 트랙백 | 덧글(0)
TMAX 윈도 스크린 샷!(오후에 배포한 이미지인듯) 어처구니가 없습니다 2

티맥스 측은 오전에 배포한 스크린 샷이 실무자의 단순 실수로 해명하고 오후에 새로운 이미지를 배포했다고 하더군요. 찾아보았더니 다음과 같은 스크린 샷이 있음을 확인 할 수 있었습니다.

74672_64232_488

위 그림을 보면 Documents and Settings 폴더가 갑자기 오전 배포하였던 그림과 다르게 Users로 바뀌었네요. 우스운 것은 탐색기가 떠 있음에도 불구하고 "작업 관리자"에는 탐색기가 떠 있음을 알리는 바(bar)가 없네요. 그리고 앞서 지적했듯이, 시작 메뉴와 탐색기가 어떻게 저렇게 나타날 수 있는지 모르겠습니다. "시작" 메뉴를 누르면 탐색기 앞으로 메뉴가 나타나고, 그림처럼 탐색기를 수행했다면 "시작" 메뉴는 사라져야 합니다. 논란이 되었던 인증서 부분도 새로운 스크린 샷이 올라 왔습니다.

 74672_64233_4858

URL 부분이 어떻게 되어 있는지 한번 보십시오. 애처롭기까지 합니다.

게다가 위에서 지적한 것과 마찬가지로 "작업 관리자에는" 브라우저가 수행되고 있음을 나타내는 바(bar)가 없네요. URL Encoding 된 부분을 한번 decoding 해보려다가 잘 보이지 않아서 포기했습니다.

여러분은 이 image가 실제 구동되고 있는 tmax 윈도로부터 capture한 스크린 샷이라고 생각하십니까?
저만 의구심을 가지는 걸까요?

by 김명신 | 2009/06/30 16:56 | 복잡한컴퓨터이야기 | 트랙백 | 덧글(3)
TMAX 윈도 스크린 샷 조작 논란에 대한 답변
디지털 데일리는 티맷스 윈도 스크린샷 조작 논란에 대해서 다음과 같은 글을 올렸군요.

티맥스 윈도 스크린샷 공개…조작 논란

저는 이 글을 보고 더 의혹이 증폭되는군요

위 글을 보면 태맥스측은 "실무진의 실수"라고 해명했다고 합니다. 그리고 "보도자료를 배포하는 과정에서 엉뚱한 이미지 파일을 첨부했다", "작은 실수로 인해 불필요한 의혹을 사고 있는 것" 이라고 했다는 군요.

엉뚱한 이미지 파일을 첨부했다고 하는데, 왜 이 "엉뚱한 이미지 파일"이 만들어졌어야 했는지에 대해서도 해명이 필요할 것이라고 생각합니다. 게다가 image 파일의 수정한 날짜등을 보면 최소한 이 이미지 파일이 2009년6월23일 혹은 그 이후에 만들어진것이라는 것을 알 수 있는데, 2009년 6월23일까지도 이 정도 스크린 샷을 보여주기 위해서 짜집기가 필요했다고 하면 7월7일 대망의 TMAX 윈도 발표회 때에는 무엇을 보여줄지 사뭇 궁금하기까지 하군요.

그리고 오후에 배포된 스크린 샷은 어디서 볼 수 있나요?
by 김명신 | 2009/06/30 16:08 | 복잡한컴퓨터이야기 | 트랙백 | 덧글(1)


< 이전페이지 다음페이지 >