정리

[Win32 API] RegEnumKeyEx

저장소/VC++

RegEnumKeyEx Function

Enumerates the subkeys of the specified open registry key. The function retrieves information about one subkey each time it is called.

LONG WINAPI RegEnumKeyEx(
  __in          HKEY hKey,
  __in          DWORD dwIndex,
  __out         LPTSTR lpName,
  __in_out      LPDWORD lpcName,
  LPDWORD lpReserved,
  __in_out      LPTSTR lpClass,
  __in_out      LPDWORD lpcClass,
  __out         PFILETIME lpftLastWriteTime
);

Parameters

hKey

A handle to an open registry key. The key must have been opened with the KEY_ENUMERATE_SUB_KEYS access right. For more information, see Registry Key Security and Access Rights.

This handle is returned by the RegCreateKeyEx, RegCreateKeyTransacted, RegOpenKeyEx, or RegOpenKeyTransacted function. It can also be one of the following predefined keys:

HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_PERFORMANCE_DATA
HKEY_USERS

Windows Me/98/95:  This parameter can also be the following value:

HKEY_DYN_DATA

dwIndex

The index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then incremented for subsequent calls.

Because subkeys are not ordered, any new subkey will have an arbitrary index. This means that the function may return subkeys in any order.

lpName

A pointer to a buffer that receives the name of the subkey, including the terminating null character. The function copies only the name of the subkey, not the full key hierarchy, to the buffer.

For more information, see Registry Element Size Limits.

lpcName

A pointer to a variable that specifies the size of the buffer specified by the lpName parameter, in TCHARs. This size should include the terminating null character. When the function returns, the variable pointed to by lpcName contains the number of characters stored in the buffer. The count returned does not include the terminating null character.

lpReserved

This parameter is reserved and must be NULL.

lpClass

A pointer to a buffer that receives the null-terminated class string of the enumerated subkey. This parameter can be NULL.

lpcClass

A pointer to a variable that specifies the size of the buffer specified by the lpClass parameter, in TCHARs. The size should include the terminating null character. When the function returns, lpcClass contains the number of characters stored in the buffer. The count returned does not include the terminating null character. This parameter can be NULL only if lpClass is NULL.

lpftLastWriteTime

A pointer to a variable that receives the time at which the enumerated subkey was last written. This parameter can be NULL.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is a system error code. If there are no more subkeys available, the function returns ERROR_NO_MORE_ITEMS.

If the lpName buffer is too small to receive the name of the key, the function returns ERROR_MORE_DATA.

Remarks

To enumerate subkeys, an application should initially call the RegEnumKeyEx function with the dwIndex parameter set to zero. The application should then increment the dwIndex parameter and call RegEnumKeyEx until there are no more subkeys (meaning the function returns ERROR_NO_MORE_ITEMS).

The application can also set dwIndex to the index of the last subkey on the first call to the function and decrement the index until the subkey with the index 0 is enumerated. To retrieve the index of the last subkey, use the RegQueryInfoKey function.

While an application is using the RegEnumKeyEx function, it should not make calls to any registration functions that might change the key being enumerated.

Note that operations that access certain registry keys are redirected. For more information, see Registry Virtualization and 32-bit and 64-bit Application Data in the Registry.

Example Code

For an example, see Enumerating Registry Subkeys.

Requirements

Client

Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, or Windows 95.

Server

Requires Windows Server 2008, Windows Server 2003, Windows 2000 Server, or Windows NT Server.

Header

Declared in Winreg.h; include Windows.h.

Library

Use Advapi32.lib.

DLL

Requires Advapi32.dll.

Unicode

Implemented as RegEnumKeyExW (Unicode) and RegEnumKeyExA (ANSI).


'저장소 > VC++' 카테고리의 다른 글

[Win32 API] RegQueryInfoKey  (0) 2010.12.16
[Win32 API] Registry Element Size Limits  (0) 2010.12.16
[Win32 API] File Version  (0) 2010.11.09
[Win32 API] System Information Functions  (0) 2010.07.16
[Win32 API] Verifying the System Version  (0) 2010.07.16

[Win32 API] File Version

저장소/VC++
DLL 또는 EXE의 File Version을 확인하는데는 3가지 API를 사용합니다.

1. DWORD GetFileVersionInfoSize(LPCTSTR lptstrFileName, LPDWORD lpdwHandle)
2. BOOL GetFileVersionInfo(LPCTSTR lptstrFileName, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
3. BOOL VerQueryValue(LPCVOID pBlock, LPCTSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen)

그리고 VS_FIXEDFILEINFO 구조체가 필요하군요.

struct VS_FIXEDFILEINFO {
DWORD dwSignature,
DWORD dwStructVersion,
DWORD dwFileVersionMS,
DWORD dwFileVersionLS,
DWORD dwProductVersionMS,
DWORD dwProductVersionLS,
DWORD dwFileFlagMask,
DWORD dwFileFlags,
DWORD dwFileOS,
DWORD dwFileType,
DWORD dwFileSubType,
DWORD dwFileDateMS,
DWORD dwFileDateLS
};

MSDN을 살펴보면 참 복잡합니다. 몇년을 봐도 복잡하네요. 영어가 싫을 뿐입니다.

예제로 살펴봅니다.

#include <Windows.h>
#include <WinVer.h>

#pragma comment(lib, "version.lib")

int _tmain(int argc, _TCHAR* argv[])
{
TCHAR* pszDestFilePath = _T("d:\\test.exe");

DWORD dwHandle = 0;
DWORD dwSize = 0;

dwSize = ::GetFileVersionInfoSize(pszDestFilePath, &dwHandle);
if(0 == dwSize)
return 1;

BYTE* pBlockData = new BYTE[dwSize];
ZeroMemory(pBlockData, dwSize);

if(FALSE == ::GetFileVersionInfo(pszDestFilePath, dwHandle, dwSize, pBlockData))
{
delete [] pBlockData;

return 1;
}

VS_FIXEDFILEINFO* pVerInfo = NULL;
UINT uLen = 0;

if(FALSE == ::VerQueryValue(pBlockData, _T("\\"), (LPVOID*)&pVerInfo, &uLen))
{
delete [] pBlockData;

return 1;
}

_tprintf_s(_T("Major Version : %d\n"), HIWORD(pVerInfo->dwFileVersionMS));
_tprintf_s(_T("Minor Version : %d\n"), LOWORD(pVerInfo->dwFileVersionMS));
_tprintf_s(_T("Release Version : %d\n"), HIWORD(pVerInfo->dwFileVersionLS));
_tprintf_s(_T("Test Version : %d\n"), LOWORD(pVerInfo->dwFileVersionLS));

delete [] pBlockData;

return 0;
}

아~ 잘 돌아가는군요. 이렇게 확인하면 되겠습니다.
더 붙이거나 뺄 것은 없는 것 같네요.
보다 자세한 사항은 MSDN을 보도록 합니다.

'저장소 > VC++' 카테고리의 다른 글

[Win32 API] Registry Element Size Limits  (0) 2010.12.16
[Win32 API] RegEnumKeyEx  (0) 2010.12.16
[Win32 API] System Information Functions  (0) 2010.07.16
[Win32 API] Verifying the System Version  (0) 2010.07.16
[Win32 API] Windows OS Version  (0) 2010.07.16

[Win32 API] System Information Functions

저장소/VC++

Function Description
DnsHostnameToComputerName Converts a DNS name to a NetBIOS name.
EnumSystemFirmwareTables Enumerates all system firmware tables of the specified type.
ExpandEnvironmentStrings Replaces environment-variable strings with their defined values.
GetComputerName Retrieves the NetBIOS name of the local computer.
GetComputerNameEx Retrieves the NetBIOS or DNS name of the local computer.
GetComputerObjectName Retrieves the local computer's name in a specified format.
GetCurrentHwProfile Retrieves the current hardware profile for the local computer.
GetFirmwareEnvironmentVariable Retrieves the value of the specified firmware environment variable from NVRAM.
GetNativeSystemInfo Retrieves information about the current system for an application running under WOW64.
GetProductInfo Retrieves the product type for the operating system on the local computer, and maps the type to the product types supported by the specified operating system.
GetSystemDirectory Retrieves the path of the system directory.
GetSystemFirmwareTable Retrieves the specified firmware table from the firmware table provider.
GetSystemInfo Retrieves information about the current system.
GetSystemRegistryQuota Retrieves the current size of the registry and the maximum size that the registry is allowed to attain on the system.
GetSystemWindowsDirectory Retrieves the path of the shared Windows directory on a multi-user system.
GetSystemWow64Directory Retrieves the path of the system directory used by WOW64.
GetUserName Retrieves the user name of the current thread.
GetUserNameEx Retrieves the name of the user or other security principal associated with the calling thread. You can specify the format of the returned name.
GetVersion Retrieves the version number of the current operating system.
GetVersionEx Retrieves information about the current operating system.
GetWindowsDirectory Retrieves the path of the Windows directory.
IsProcessorFeaturePresent Determines whether a processor feature is supported by the current computer.
IsWow64Message Determines whether the last message read from the queue of the current process originated from a WOW64 process.
IsWow64Process Determines whether a process is running under WOW64.
SetComputerName Sets a new NetBIOS name for the local computer.
SetComputerNameEx Sets a new NetBIOS or DNS name for the local computer.
SetFirmwareEnvironmentVariable Sets the value of the specified firmware environment variable in NVRAM.
TranslateName Converts a directory service object name from one format to another.
VerifyVersionInfo Compares a set of version requirements to the values for the current operating system.
VerSetConditionMask Builds the condition mask for the VerifyVersionInfo function.
Wow64DisableWow64FsRedirection Disables file system redirection for the calling thread.
Wow64EnableWow64FsRedirection Enables or disables file system redirection for the calling thread.
Wow64RevertWow64FsRedirection Restores file system redirection for the calling thread.

'저장소 > VC++' 카테고리의 다른 글

[Win32 API] RegEnumKeyEx  (0) 2010.12.16
[Win32 API] File Version  (0) 2010.11.09
[Win32 API] Verifying the System Version  (0) 2010.07.16
[Win32 API] Windows OS Version  (0) 2010.07.16
[Win32 API] 64bit OS인지 확인하려면 IsWow64Process  (0) 2010.07.15

[Win32 API] Verifying the System Version

저장소/VC++

Windows의 Version 및 SP 버전을 확인하고자 할 때는 VerifyVersionInfo API를 이용하면 된다.

MSDN에서 발췌해온 아래 샘플을 참고하자.

[Example 1]

#include <windows.h>
#include <stdio.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);
}

void main()
{
    if(Is_WinXP_SP2_or_Later())
        printf("The system meets the requirements.\n");
    else printf("The system does not meet the requirements.\n");
}


[Example 2]

#include <windows.h>
#include <stdio.h>

BOOL Is_Win_Server()
{
   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 = 0;
   osvi.wServicePackMajor = 0;
   osvi.wServicePackMinor = 0;
   osvi.wProductType = VER_NT_SERVER;

   // 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 );
   VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );

   // Perform the test.

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

void main()
{
    if(Is_Win_Server())
        printf("The system meets the requirements.\n");
    else printf("The system does not meet the requirements.\n");
}

[Win32 API] Windows OS Version

저장소/VC++

Operating system Version number
Windows 7 6.1
Windows Server 2008 R2 6.1
Windows Server 2008 6.0
Windows Vista 6.0
Windows Server 2003 R2 5.2
Windows Server 2003 5.2
Windows XP 64-Bit Edition 5.2
Windows XP 5.1
Windows 2000 5.0


MSDN에서 퍼온 샘플을 보면 이해가 빠를듯 하다.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

#pragma comment(lib, "User32.lib")

#define BUFSIZE 256

typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);

BOOL GetOSDisplayString( LPTSTR pszOS)
{
   OSVERSIONINFOEX osvi;
   SYSTEM_INFO si;
   PGNSI pGNSI;
   PGPI pGPI;
   BOOL bOsVersionInfoEx;
   DWORD dwType;

   ZeroMemory(&si, sizeof(SYSTEM_INFO));
   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));

   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

   if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
      return 1;

   // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.

   pGNSI = (PGNSI) GetProcAddress(
      GetModuleHandle(TEXT("kernel32.dll")),
      "GetNativeSystemInfo");
   if(NULL != pGNSI)
      pGNSI(&si);
   else GetSystemInfo(&si);

   if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId &&
        osvi.dwMajorVersion > 4 )
   {
      StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));

      // Test for the specific product.

      if ( osvi.dwMajorVersion == 6 )
      {
         if( osvi.dwMinorVersion == 0 )
         {
            if( osvi.wProductType == VER_NT_WORKSTATION )
                StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
            else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
         }

         if ( osvi.dwMinorVersion == 1 )
         {
            if( osvi.wProductType == VER_NT_WORKSTATION )
                StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
            else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
         }
        
         pGPI = (PGPI) GetProcAddress(
            GetModuleHandle(TEXT("kernel32.dll")),
            "GetProductInfo");

         pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);

         switch( dwType )
         {
            case PRODUCT_ULTIMATE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
               break;
            case PRODUCT_PROFESSIONAL:
               StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
               break;
            case PRODUCT_HOME_PREMIUM:
               StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
               break;
            case PRODUCT_HOME_BASIC:
               StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
               break;
            case PRODUCT_ENTERPRISE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
               break;
            case PRODUCT_BUSINESS:
               StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
               break;
            case PRODUCT_STARTER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
               break;
            case PRODUCT_CLUSTER_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
               break;
            case PRODUCT_DATACENTER_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
               break;
            case PRODUCT_DATACENTER_SERVER_CORE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
               break;
            case PRODUCT_ENTERPRISE_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
               break;
            case PRODUCT_ENTERPRISE_SERVER_CORE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
               break;
            case PRODUCT_ENTERPRISE_SERVER_IA64:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
               break;
            case PRODUCT_SMALLBUSINESS_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
               break;
            case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
               StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
               break;
            case PRODUCT_STANDARD_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
               break;
            case PRODUCT_STANDARD_SERVER_CORE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
               break;
            case PRODUCT_WEB_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
               break;
         }
      }

      if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
      {
         if( GetSystemMetrics(SM_SERVERR2) )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
         else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
         else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
         else if( osvi.wProductType == VER_NT_WORKSTATION &&
                  si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
         {
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
         }
         else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));

         // Test for the server type.
         if ( osvi.wProductType != VER_NT_WORKSTATION )
         {
            if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
            {
                if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
                else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
            }

            else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
            {
                if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
                else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
                else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
            }

            else
            {
                if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
                else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
                else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
                else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
                else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
            }
         }
      }

      if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
      {
         StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
         if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
         else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
      }

      if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
      {
         StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));

         if ( osvi.wProductType == VER_NT_WORKSTATION )
         {
            StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
         }
         else
         {
            if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
               StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
            else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
               StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
            else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
         }
      }

       // Include service pack (if any) and build number.

      if( _tcslen(osvi.szCSDVersion) > 0 )
      {
          StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
          StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
      }

      TCHAR buf[80];

      StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
      StringCchCat(pszOS, BUFSIZE, buf);

      if ( osvi.dwMajorVersion >= 6 )
      {
         if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
            StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
         else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
            StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
      }
     
      return TRUE;
   }

   else
   { 
      printf( "This sample does not support this version of Windows.\n");
      return FALSE;
   }
}

int __cdecl _tmain()
{
    TCHAR szOS[BUFSIZE];

    if( GetOSDisplayString( szOS ) )
        _tprintf( TEXT("\n%s\n"), szOS );
}

[Win32 API] 64bit OS인지 확인하려면 IsWow64Process

저장소/VC++
64bit OS의 확인은 IsWow64Process API를 사용하면 된다.
(중요한 것은 Client는 XP SP2 이상부터, Server는 2003 SP1 부터 지원된다는 것이다.
사용 전 주의가 필요하다.)

API 원형은 다음과 같다.

BOOL WINAPI IsWow64Process(
__in HANDLE hProcess,
__out PBOOL Wow64Process );

Parameters

hProcess

A handle to the process.

Wow64Process

A pointer to a value that is set to TRUE if the process is running under WOW64. Otherwise, the value is set to FALSE.

Return Value

If the function succeeds, the return value is a nonzero value.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the application is a 64-bit application running under 64-bit Windows, the Wow64Process parameter is set to FALSE.

To compile an application that uses this function, define _WIN32_WINNT as 0x0501 or later. For more information, see Using the SDK Headers.


샘플 코드는 다음과 같다.
MSDN 발췌
#include <windows.h>
#include <stdio.h>

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
    BOOL bIsWow64 = FALSE;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
  
    if (NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            // handle error
        }
    }
    return bIsWow64;
}

void main()
{
    if(IsWow64())
        printf("Running on WOW64\n");
    else printf("Running on 32-bit Windows\n");
}

[Win32 API] GetSystemTime과 GetLocalTime

저장소/VC++

시간을 확인할 때 사용하는 API들이다.
다른 것도 있지만 제일 편하다.
하지만 두 API는 서로 다른 시간을 가진다.

GetLocalTime은 현재 컴퓨터의 시간을 반환하지만
GetSystemTime은 UTC 표준 시간을 반환한다.

API 이름만 놓고 생각해보면 둘다 같은 것 같으면서도 다르다.
요거요거.. 차이점 모르고 썼다가 귀찮아졌다.

MSDN 천천히 읽고 써야겠다. ㅠㅠ

SVN 설치 및 운용

Linux
windows에서 SVN과 apache 운용


CentOS에서 SVN Server의 설치 및 운용에 대한 기록.

1. 설치
매우 쉽다.

]# yum install subversion

이거면 된다.

2. 운용
2.1 Repository(저장소) 생성

]# svnadmin create --fs-type fsfs [Repository Path]

위와 같은 명령을 통해서 [Repository Path]에 Repository가 생성된다.

2.2 설정

Repository 디렉토리에 사용자/그룹 위임을 설정합니다.
]# chown -R svn:svn /home/svn/[Repository Name]

파일을 수정하여 [general] Section을 수정한 뒤 상황에 맞게 다음 파일들을 수정해준다.
]# vi [Repository Path]/conf/svnserve.conf

사용자 계정 설정
]# vi  [Repository Path]/conf/passwd

계정별 접근 권한 등의 설정
]# vi [Repository Path]/conf/authz

2.3 SVN Server의 시작

 ]# svnserve -d -r /home/svn

프로세스 동작 여부를 확인하고 3690 port가 대기 중인지 확인한다.
(SVN Server는 기본적으로 3690 port를 사용한다.)

]# ps -aux | grep svnserve
]# netstat -ant | grep 3690

2.4 Service 등록
시스템 부팅 시 자동으로 시작되게 하기 위해서는 우선 스크립트 파일을 수정해줘야 한다.

]# vi /etc/rc.d/init.d/svnserve

Repository 경로가 지정되어있지 않기 때문에 인자를 추가하여 해당 경로를 지정해줘야한다.

스크립트를 살펴보면 다음과 같은 내용을 찾을 수 있다.

args="--daemon --pid-file=${pidfile} $OPTIONS"

바로 윗줄에

OPTIONS="--threads --root /home/svn"

를 추가해주고 저장한뒤 편집을 종료한다.

수정 후 다음과 같이 등록하면 시스템이 시작될 때 자동으로 동작하게 된다.

]# chkconfig --level 2345 svnserve on

3. 사용
Windows에서 Repository에 접근하기 위해서는 SVN Client를 필요로 한다.
많은 종류의 Client들이 있지만 가장 보편적으로 쓰이는 Tortois SVN을 쓰면 된다.









Debugging Tools for Windows - WinDbg

저장소/잡다한거

Download Link
http://www.microsoft.com/whdc/devtools/debugging/default.mspx


디버깅의 기초? 라고 하기는 좀 그렇지만
유용하게 활용할 수 있는 툴.

[C++] __stdcall, __cdecl 그리고 Calling Convention

저장소/VC++
내용 직접 정리해야 하는데... 일단 펌질 ㅎㅎ



[출처] cafe.naver.com/win32cpp


Keyword Stack cleanup Parameter passing
__cdecl Caller Pushes parameters on the stack, in reverse order (right to left)
__stdcall Callee Pushes parameters on the stack, in reverse order (right to left)
__fastcall Callee Stored in registers, then pushed on stack
thiscall
(not a keyword)
Callee Pushed on stack; this pointer stored in ECX



함수호출 방식이 __cdecl, __pascal, __stdcall로 여러 가지가 있는 이유는 윈도우즈의 역사성에 있다. 우선 win16에서는 실행파일의 크기가 줄어들고 속도가 빠르다는 이유로 pascall 방식을 사용 했고 win32에서는 가변매개인자를 지원하는 함수를 제외한 모든 함수들은 __stdcall을 사용 한다. 만약 c 방식의 함수호출을 원한다면 __cdecl을 명시해 주어야 한다.(윈도우즈 프로그래밍에 있어서) 우선 c 방식의 함수 호출과 pascal 방식의 함수호출의 차이점을 알아보자. 첫 번째로 함수호출후 종료 시점에 호출한 함수의 스택을 정리하는 주체가 호출한 함수이냐 아니면 호출당한 함수이냐의 차이이다. 두 번째는 매개인자를 스택에 넣는 방향에 따라 나눈다. 즉, 다음과 같이 정리할 수가 있다.

(언더바는 생략가능함 )
1.인수를 스택에 집어넣는 방향에 따라서 다음과 같이 나뉘고
       pascal : 인수를 스택에 저장하는 순서를 왼쪽에서 오른쪽으로 한다.
       cdecl : 인수를 스택에 저장하는 순서를 오른쪽에서 왼쪽으로 한다.
      stdcall : 인수를 스택에 저장하는 순서를 오른쪽에서 왼쪽으로 한다.
2.스택에 인수를 pop 하는 주체에 따라서 다음과 같이 나뉘고.
      pascal : 호출을 당하는 쪽이 스택공간을 삭제한다.
      stdcall : 호출을 당하는 쪽이 스택공간을 삭제한다.
     cdecl : 호출을 하는 쪽이 스택공간을 삭제한다.
이렇게 stdcall은 pascal방식과 cdecl방식을 혼합한 형태를 띄운다
자 이제는 WinMain함수를 살펴보자 일반적으로 WinMain은 다음과 같이 선언되어 있다.

int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )

APIENTRY는 WINAPI와 같은 형식을 나타낸다. 이것은 FAR __stdcall로 정의되어 있다. 또한 참고로 CALLBACK은 __stdcall로 정의되어 있다. 그럼 WINAPI와 __cdecl 함수의 호출 방식의 차이점을 예제로 알아보도록 하자. 아래에 두 방식으로 호출되는 간단한 예제가 있다.

#include "stdafx.h"

int __stdcall func(int i,int j);
int __cdecl func2(int i,int j);


int _tmain(int argc, _TCHAR* argv[])
{
        func(1,2);
        func2(2,3);

        return 0;
}

int __stdcall func(int i,int j)
{
        int r;
        r=i+j;
        return r;
}

int __cdecl func2(int i,int j)
{
        int r;
        r=i+j;
        return r;
}


이 함수들을 호출하는 부분을 디스어셈블 해 보갰다.


        func(1,2);
00411A1E  push        2    
00411A20  push        1    
00411A22  call        func (411069h)
        func2(2,3);
00411A27  push        3    
00411A29  push        2    
00411A2B  call        func2 (4110FFh)
00411A30  add         esp,8 <-------------- cdecl의 함수호출의 경우는 이 부분이 추가됨
        return 0;
...
...
00411AA0  ret         8    <------- func가 종료될 때
...
00411AE0  ret              <--------func2가 종료될때
...

위에 보면은 func를 호출할 때는 없는 코드가 func2에는 있는 것을 볼 수가 있다. 바로 스택을 정리 해주는 코드이다. add         esp,8 이라는 것이다. 모든 함수 호출 형식이 이와 같았다면.. 실행 화일 코드에 add         esp,8라는 명령어가 더 들어가게 된다. 따라서 이 코드가 존재하지 않는 pascall 방식이 실행크기가 작아지게 된 것이다. 파스칼 호출 방식은 속도도 저 명령어 하나 만큼 빨라지게 되는 것이다. 여기에는 8086 아키텍쳐에 관련된 명령어가 그 원인으로 등장한다. 그리고 스택을 정리한다는 것 자체가 그 함수를 호출한 뒤에 add         esp,8으로 스택포인터를 인자의 크기만큼 변경을 시킨다는 이야긴데...근데 여기서 프로시저 즉 함수를 다 수행했을때 원래 상태로 돌아가게 될 때 쓰이는 명령어는 ret이다. 함수 시작하고, 함수가 끝났을때 ret 명령어로 호출한 부분으로 넘어가게 된다. 다시 말하면 이 명령어는 실행되던 함수를 바로 빠져나가게 된다. 따라서.. 스택을 정리할 시간이 전혀 없다. 이에 8086설계자들은 함수에서 리턴이 될 때 스택포인터(SP)를 적절한 위치로 리셋을 시킬 수 있는 ret명령어를 새로 제공을 하여 이 문제를 아주 손쉽게 해결해 버렸다. 즉 ret, n 이라는 명령어를 제공했다는 셈이다..

어차피 리턴할 걸 스택 포인터가 정리되는 부분으로 아예 리턴을 해버리란 이야기다.. 이것은 가만히 앉아서 프로그램의 속도와 크기를 이점을 살리는 것이다.

add         esp,8   ; -->> 추가된 코드..

호출하는 부분에서 이렇게 코딩하는 대신 호출 받는부분에서 리턴할때 ret, 8으로 해결했다는 것이다.
이래서 속도가 더빨라지는 것이다. 크기도 줄어들고..... 생각을 한번 해보자..... 이런식의 함수가 굉장히 많이 호출된다면..  크기나 실행 시간이 증가되는건 당연하지 않겠는가 ? 이 이유로 속도와 크기가 아주 중요시 되던 시절에(windows 3.0, 3.1이 널리 사용되던 시절에) OS/2와 Windows설계자들은 API함수를 설계할때 프로그램이 느려지고 크기가 커지는 C방식을 사용하지 않고 pascal이나 fortran이 사용하고 있는 방식으로 스택 프레임을 설계 하게 되었다. 바로 이런 이유가 바로 pascal방식에 비교해서 바로 cdecl의 단점이 되는 것이다. 자 이번에는 다시 위의 cdecl 호출의 장점을 보게 되면.. 가변매개인자를 사용할 수가 있다는 것인데... 즉, 매개인자를 오른쪽에서 왼쪽으로 집어 넣는 것이 왜 중요한가? 이다.

이것은 인자의 첫번째가 어디인지 확실하다는 것이다. 즉 알려진 장소에서 첫번째 인자를 찾아낼 수 있다는 장점으로 가변인자를 허용할 수 있다. 호출이 되었을대 스택의 맨 상위부분이 인자의 첫번째임은 확실하니까.... 이것이 cdecl방식의 장점이 되는 것이다. 함수호출이 끝난후 스택을 정리할 때 호출한쪽에서는 정확하게 Stack을 사용한 사이즈를 알고있기 때문에 문제가되지 않지만 호출당한쪽에서는 또다른 정보를 가지고 사용한 Stack의 사이즈를 알아야 하기 때문에 심각한 문제가 발생할수 있다는 것이다. 그러기 때문에 stdcall은 함수호출 방식은 파스칼을 따르고 있지만 가변매개인자는 지원하지 못하는 것이다. 가변매개인자를 꼭 사용해야만 한다면 반드시 cdecl을 사용해야만 한다.