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 과 같음