본문 바로가기

프로그래밍/코드 조각

윈도우 버전 구하기 (두번째)

EXE 에서는 이 포스팅에서 나온대로 manifest를 추가하면 정상적으로 윈도우 버전을 가져 올 수 있다.


하지만 DLL로 모듈을 생성할 경우 EXE에 종속된 manifest를 따라가기 때문에 내가 의도한 대로 윈도우 버전을 얻을 수 없다.


이 경우 WMI를 통해서 정상적인 윈도우 버전을 얻을 수 있다.


#include <wbemidl.h>


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


bool CreateLocalConnection(bool set_blanket,

                           IWbemServices** wmi_services) {

  base::win::ScopedComPtr<IWbemLocator> wmi_locator;

  HRESULT hr = wmi_locator.CreateInstance(CLSID_WbemLocator, NULL,

                                          CLSCTX_INPROC_SERVER);

  if (FAILED(hr))

    return false;


  base::win::ScopedComPtr<IWbemServices> wmi_services_r;

  hr = wmi_locator->ConnectServer(base::win::ScopedBstr(L"ROOT\\CIMV2"),

                                  NULL, NULL, 0, NULL, 0, 0,

                                  wmi_services_r.Receive());

  if (FAILED(hr))

    return false;


  if (set_blanket) {

    hr = ::CoSetProxyBlanket(wmi_services_r,

                             RPC_C_AUTHN_WINNT,

                             RPC_C_AUTHZ_NONE,

                             NULL,

                             RPC_C_AUTHN_LEVEL_CALL,

                             RPC_C_IMP_LEVEL_IMPERSONATE,

                             NULL,

                             EOAC_NONE);

    if (FAILED(hr))

      return false;

  }


  *wmi_services = wmi_services_r.Detach();

  return true;

}


std::string WMIWindowsVersion::GetVersion() {

  ScopedCOMInitializer com_initializer;

  HRESULT hr = ::CoInitializeSecurity(NULL,

                                     -1,                          // COM authentication

                                     NULL,                        // Authentication services

                                     NULL,                        // Reserved

                                     RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 

                                     RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  

                                     NULL,                        // Authentication info

                                     EOAC_NONE,                   // Additional capabilities 

                                     NULL);                       // Reserved


  if (FAILED(hr) && (hr != RPC_E_TOO_LATE))

    return std::string();


  base::win::ScopedComPtr<IWbemServices> services;

  if (!CreateLocalConnection(true, services.Receive()))

    return std::string();


  base::win::ScopedBstr query_language(L"WQL");

  base::win::ScopedBstr query(L"SELECT Version FROM Win32_OperatingSystem");

  base::win::ScopedComPtr<IEnumWbemClassObject> enumerator;

  hr = services->ExecQuery(

      query_language, query,

      WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL,

      enumerator.Receive());

  if (FAILED(hr) || !enumerator)

    return std::string();


  base::win::ScopedComPtr<IWbemClassObject> class_object;

  ULONG items_returned = 0;

  hr = enumerator->Next(WBEM_INFINITE, 1, class_object.Receive(),

                        &items_returned);

  if (!items_returned)

    return std::string();


  base::win::ScopedVariant version;

  class_object->Get(L"Version", 0, version.Receive(), 0, 0);


  base::string16 version_string;

  if (version.type() == VT_BSTR) {

    version_string = V_BSTR(&version);

  }

  else if (version.type() == VT_UI2) {

    wchar_t buffer[32] = { 0, };

    _itow_s(version.AsInput()->uiVal, &buffer[0], 20, 10);

    version_string = buffer;

  }

  else if (version.type() == VT_I4) {

    wchar_t buffer[32] = { 0, };

    _itow_s(version.AsInput()->uiVal, &buffer[0], 20, 10);

    version_string = buffer;

  }


  return UTF16ToUTF8(version_string);

}



ScopedCOMInitializer, ScopedBstr, ScopedComPtr, ScopedVariant 함수는 생성자 소멸자를 통해 리소스 할당/해제를 하는 는 클래스입니다.

-> _bstr_t, _variant_t, ComPtr 등의 클래스로 대체 가능

base::string16 은 std::wstring 과 같음