2017-06-20 88 views
1

假設我正在寫一機多用的DLL,其中包括用於獲取操作系統版本的函數:從dll函數調用中正確獲取Windows版本?

void get_os_version(DWORD *major, DWORD *minor) 
{ 
    OSVERSIONINFOEX osvi; 

    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); 
    osvi.dwOsVersionInfoSize = sizeof(OSVERSIONINFOEX); 

    // deprecated but easier to use for this example's sake 
    GetVersionEx((OSVERSIONINFO*)&osvi); 

    *major = osvi.dwMajorVersion; 
    *minor = osvi.dwMinorVersion; 
} 

對於Windows版本比Windows 8以上版本被正確檢索,需要嵌入清單,指定支持的平臺(請參閱詳細信息here)。

所以我禁用自動生成清單的編制時,使用/MANIFEST:NO標誌我的DLL文件,而不是添加下面的清單:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> 
     <security> 
      <requestedPrivileges> 
       <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel> 
      </requestedPrivileges> 
     </security> 
    </trustInfo> 
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
     <application> 
      <!-- Windows 10 --> 
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> 
      <!-- Windows 8.1 --> 
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> 
      <!-- Windows Vista --> 
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
      <!-- Windows 7 --> 
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> 
      <!-- Windows 8 --> 
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> 
     </application> 
    </compatibility> 
</assembly> 

,使用MT工具:

mt -manifest GetOsVersion.dll.manifest -outputresource:GetOsVersion.dll;#2 

一切順利,沒有錯誤。現在使用DLL,我創建了一個簡單的APP.EXE其加載DLL並調用其功能:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    DWORD major, minor; 
    get_os_version(&major, &minor); 
    printf("%d.%d\n", major, minor); 
    return 0; 
} 

但在Windows 10,驚喜驚喜運行APP.EXE時,輸出爲:

6.2 

,這是版本的Windows 8,如果我申請的艙單APP.EXE太:

mt -manifest GetOsVersion.dll.manifest -outputresource:App.exe;#1 

,產量預期之一:

10.0 

這是爲什麼發生?我可以在不向可執行文件添加清單的情況下解決此問題嗎?

我無法控制將使用我的庫的應用程序,但我仍然想要正確檢索操作系統版本。

回答

1

用於確定實際的操作系統版本的另一種方法是在MSDN頁"Getting the System Version"上記載:

要獲得完整版操作系統編號,在其中一個系統DLL(如Kernel32.dll)上調用GetFileVersionInfo函數,然後調用VerQueryValue以獲取文件版本信息的\\StringFileInfo\\<lang><codepage>\\ProductVersion子塊。

這將從DLL工作,無論應用程序是否具有清單。 (當然,GetVersionInfo和朋友不會返回實際的操作系統版本是有原因的:程序員有濫用這些信息的惡意傾向,你應該認真考慮是否在你的DLL中提供這樣的函數真是個好主意)

+0

+1謝謝,我會試試這個。注意:我不會在我的實際dll中導出這樣的函數,它會在dll中調用以進行統計和調試;我這樣做了這個例子,以便我可以很容易地展示問題 – Claudiu

+0

好的,那是合法的用法。我不會編輯我的答案,因爲警告可能仍然與未來的讀者有關。 :-) –

1

App (executable) manifest MSDN page描述了這個問題,而明確:

應用程序(可執行文件)的兼容性部分在Windows清單推出有助於操作系統確定應用程序的目的是針對Windows版本。

如果清單不是可執行清單,則兼容性(以及其他應用程序設置,如DPI知曉)完全被忽略。這是有道理的,因爲否則在不同dll中清單之間可能會出現明顯的衝突。

+0

非常感謝,不允許將這樣的清單標籤放入dll中。但是,似乎沒有可靠的方式從DLL獲取操作系統版本... – Claudiu

0

大多數在清單節點適用於整個過程,只從主.EXE模塊讀取:

compatibility section of the app (executable) manifest是在Windows幫助操作系統來決定Windows版本的應用程序是旨在針對。

您應該使用GetProcAddressCoCreateInstance檢查,如果你需要的功能存在,而不是Windows版本。

通過一些工作,GetProcAddress也可以用來確定你是否真的需要這些信息。看看MSDN上的各種KERNEL32以及USER32功能的最低操作系統版本...

+0

事情是我不想針對特定版本的Windows我的應用程序,我只想獲得Windows版本。 (所以是的,我的假設是我得到的Windows版本實際上是錯誤的) – Claudiu

+0

如果您將它寫入日誌文件但是您不應該使用它來決定可以調用哪些API,那麼獲取Windows版本是可以的。 – Anders

1

補充了accepted answer,這裏是誰比誰都想實現它的一些啓動代碼:

#pragma comment(lib, "version") 

static void print_version() 
{ 
    DWORD buffer_size = GetFileVersionInfoSize(_T("kernel32.dll"), NULL); 
    if (buffer_size == 0) 
    { 
     // get error from GetLastError() 
     return; 
    } 

    VOID *buffer = malloc(buffer_size); 
    if (buffer == NULL) 
    { 
     // out of memory 
     return; 
    } 

    if (!GetFileVersionInfo(_T("kernel32.dll"), 0, buffer_size, buffer)) 
    { 
     goto error; 
    } 

    VS_FIXEDFILEINFO *version = NULL; 
    UINT version_len = 0; 
    if (!VerQueryValue(buffer, 
         _T("\\"), 
         (LPVOID*)&version, 
         &version_len)) 
    { 
     goto error; 
    } 

    _tprintf(_T("Version is: %u.%u\n"), 
      HIWORD(version->dwProductVersionMS), 
      LOWORD(version->dwProductVersionMS)); 

error: 
    free(buffer); 
} 

和Windows 10的輸出:

Version is 10.0