Solaris 10: Alternative to dirfd() - c++

I had worked on RHEL 6.5 and developed some code which would use the function dirfd() for readdir_r(), like shown below:
#include <dirent.h>
#include <sys/types.h>
void some_function(){
DIR *dir = NULL;
struct dirent *pentry = NULL, *next_file = NULL;
if ((dir = opendir("/ZB_RQ/")) != NULL) {
len_pentry = offsetof(struct dirent, d_name) + fpathconf(dirfd(dir), _PC_NAME_MAX) + 1;
pentry = malloc(len_pentry);
if(!pentry){
exit(0);
}
for(;;){
readdir_r(dir, pentry, &next_file);
if(!next_file){
//No file to iterate.
break;
}
else{
// do something
}
}
}
}
This piece of codes work fine in RHEL 6.5 (Linux) but when I run this in Oracle Solaris 10, it fails with an error Undefined symbol dirfd.
I have searched this fucntion in /usr/include/dirent.h but it is not there. The same is available in dirent.h version of Linux.
I have read somewhere that dirfd() is not available in Solaris 9 and 10.
So, is there any equivalent workaround of this function in Solaris 10?

This late BSD function was standardized in 2008 while Solaris 9 was released in 2001 and Solaris 10 in 2005. That's the reason why it isn't available with these versions.
dirfd is available with the current version, Solaris 11.
For older ones, reimplementing dirfd seems to be obvious, given the fact the file descriptor is already in the passed structure, here dir->d_fd or dir->dd_fd depending on whether __XOPEN_OR_POSIX is defined or not.

Related

fopen_s returns error code 2 with system account and win 32 but works fine on winx64 (c++)

I have a cpp program that uses fopen_s to open and read a file created under the directory C:\Windows\System32\config\systemprofile\AppData\Roaming.
My program needs to be compatible with winx64 and win32.
When I run this program with a system account (run using PSTools\PSExec -i -s C:\windows\system32\cmd.exe) and the Win32 compiled version of the program, fopen_s() on any file inside "C:\Windows\System32\config\systemprofile\AppData\Roaming" returns an error code 2, even though the file is present.
However, when I run the x64 compiled version of the same program, it works fine and fopen_s() is able to find and open the same file.
I am sure there are no mistakes as far as passing a valid filename to fopen_s() and I have verified this.
I make sure that the int variable that stores the return value from fopen_s() is set to 0 every time before calling fopen_s(). I am calling fopen_s() in "r" mode.
Also, elsewhere in the same program I am able to create files under the same directory.
I am using VS2019 and cpp +11 to compile my program.
My system is running windows 10 (64-bit) on an x64 processor (Intel(R) Xeon(R) Gold 6136)
Why would a win32 application fail to read a file created under "C:\Windows\System32\config\systemprofile\AppData\Roaming" with a system account while the x64 version of the same application works fine?
Code snippet:
int FileOpenFunc(FILE ** ppFile, std::string sFilename, std::string sOpenMode)
{
int errOpen = 0;
#ifdef _WIN32
errOpen = fopen_s(ppFile, sFilename.c_str(), sOpenMode.c_str());
#else
*ppFile = fopen(sFilename.c_str(), sOpenMode.c_str());
errOpen = errno;
#endif
return errOpen;
}
void func()
{
std::string sFileName = "C:\\Windows\\System32\\config\\systemprofile\\AppData\\Roaming\\Check\\sample.txt";
int errFopenErrNo = 0;
FILE* fp = NULL;
errFopenErrNo = FileOpenFunc(&fp, sFileName, "r");
if (fp!= NULL)
{
//do something
}
else
{
//do something else
}
}

Is there a new replacement for SHGetSpecialFolderLocation?

My app is written in C++Builder for Win32. My code uses the SHGetSpecialFolderLocation() API to get the CSIDL_APPDATA and CSIDL_MYDOCUMENTS paths.
I noticed on Microsoft's website dated 12/04/2018 that it says:
[SHGetSpecialFolderLocation is not supported and may be altered or unavailable in the future. Instead, use SHGetFolderLocation.]
Then for SHGetFolderLocation it says:
Deprecated
What is the current way to get these two paths?
My current code is below.
LPITEMIDLIST List = NULL;
wchar_t wPath[MAX_PATH + 1];
UnicodeString S01, Fi;
if( !SHGetSpecialFolderLocation(0, CSIDL_APPDATA, &List) ){
if( SHGetPathFromIDListW(List, wPath ) ){
S01 = wPath;
Fi = (S01+"\\my_files\\");
Form1->MyRoamingPath_Mh = Fi;
}
}
SHGetSpecialFolderLocation() was first introduced in Windws 95/NT4. It was deprecated in Windows 2000/XP in favor of SHGetFolderLocation() (which returns a folder location as an IDLIST_ABSOLUTE) and SHGetFolderPath() (which returns a folder location as a path string).
So, in your example, you could have used SHGetFolderPath() instead:
#include <Shlobj.h>
#include <SysUtils.hpp>
wchar_t wPath[MAX_PATH + 1];
if (SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK)
{
Form1->MyRoamingPath_Mh = IncludeTrailingPathDelimiter(wPath) + L"my_files\\";
}
In Vista, use of CSIDL was deprecated in favor of KNOWNFOLDERID. The above functions have been deprecated in favor of SHGetKnownFolderIDList()/IKnownFolder::GetIDList() and SHGetKnownFolderPath()/IKnownFolder::GetPath(), respectively.
This is actually stated at the bottom of the SHGetFolderLocation() documentation 1:
1: I guess you did not scroll down far enough to see it.
Note As of Windows Vista, this function is merely a wrapper for SHGetKnownFolderIDList. The CSIDL value is translated to its associated KNOWNFOLDERID and SHGetKnownFolderIDList is called. New applications should use the known folder system rather than the older CSIDL system, which is supported only for backward compatibility.
So, in your example, you can now use SHGetKnownFolderPath() instead:
#include <Shlobj.h>
#include <SysUtils.hpp>
PWSTR pwPath;
if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &pwPath) == S_OK)
{
try
{
Form1->MyRoamingPath_Mh = IncludeTrailingPathDelimiter(pwPath) + L"my_files\\";
}
__finally
{
CoTaskMemFree(pwPath);
}
}
For the "My Documents" folder, use FOLDERID_Documents.

C++ RegGetValue function not returning correct Windows OS Version

I'm using the below code in a console application to get my Windows OS version:
#include <string>
#include <iostream>
#include <Windows.h>
int main()
{
DWORD dataSize = 0;
char buffer[256];
dataSize = sizeof(buffer);
RegGetValueA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
"ProductName", RRF_RT_REG_SZ, 0, &buffer, &dataSize);
cout << buffer << endl;
return 0;
}
I have Windows 10 Pro installed, but the function is returning Windows 10 Enterprise. I have even manually navigated using regedit to the specified key and under "Product Name" I can see Windows 10 Pro. Here is an image of my regedit.
I ran another function RtlGetProductInfo(10, 0, 0, 0, f); and it returned the value of 0x48 for f, which according to Microsoft I have Windows 10 Enterprise Evaluation.
Now, at this point, I understand that something is messed up with my Windows installation, but why would my first code return another value than what is displayed for "ProductName" in my registry editor?
Edit: I should add that I've run the code on another Windows PC and it returns the correct version on that computer.

C++ How to detect Windows 10

I have written a PC auditing tool many years ago and have been keeping it up to date. One of basic functions is reporting the version of Windows running on the PC being audited for which I have always used the GetVersionEx call.
This works up to and including Windows 8 but is not supported under Windows 10 and indeed Windows 10 returns 8.2 just as windows 8 does. Microsoft do not seem to have introduced anything as a direct replacement suggesting instead that you check for specific features required rather than looking at the OS but for the purpose of the audit I actually want the OS name.
The 'scanner' is a C++ program which must run under non-privileged accounts so I don't think another suggestion I have read - picking up the version of a system DLL such as kernel32.dll will work as these folders are typically not accessible to users.
Any other suggestions/thoughts are most welcome!
Starting in Windows 8.1, GetVersion() and GetVersionEx() are subject to application manifestation:
With the release of Windows 8.1, the behavior of the GetVersionEx API has changed in the value it will return for the operating system version. The value returned by the GetVersionEx function now depends on how the application is manifested.
Applications not manifested for Windows 8.1 or Windows 10 will return the Windows 8 OS version value (6.2). Once an application is manifested for a given operating system version, GetVersionEx will always return the version that the application is manifested for in future releases. To manifest your applications for Windows 8.1 or Windows 10, refer to Targeting your application for Windows.
The newer Version Helper functions are simply wrappers for VerifyVersionInfo(). Starting in Windows 10, it is now subject to manifestation as well:
Windows 10: VerifyVersionInfo returns false when called by applications that do not have a compatibility manifest for Windows 8.1 or Windows 10 if the lpVersionInfo parameter is set so that it specifies Windows 8.1 or Windows 10, even when the current operating system version is Windows 8.1 or Windows 10. Specifically, VerifyVersionInfo has the following behavior:
If the application has no manifest, VerifyVersionInfo behaves as if the operation system version is Windows 8 (6.2).
If the application has a manifest that contains the GUID that corresponds to Windows 8.1, VerifyVersionInfo behaves as if the operation system version is Windows 8.1 (6.3).
If the application has a manifest that contains the GUID that corresponds to Windows 10, VerifyVersionInfo behaves as if the operation system version is Windows 10 (10.0).
The Version Helper functions use the VerifyVersionInfo function, so the behavior IsWindows8Point1OrGreater and IsWindows10OrGreater are similarly affected by the presence and content of the manifest.
To manifest your applications for Windows 8.1 or Windows 10, see Targeting your application for Windows.
To get the true OS version regardless of manifestation use RtlGetVersion(), NetServerGetInfo(), or NetWkstaGetInfo() instead. They all report an accurate OS version and are not subject to manifestation (yet?).
(Microsoft used to suggest querying the file version of a system DLL, but they stopped recommending that when Windows didn't update system DLL versions to match.)
GetVersion and GetVersionEx were superseded by various version helper functions. The one you want is IsWindows10OrGreater. They can be found in VersionHelpers.h.
IsWindows10OrGreater is only available in the latest SDK/Visual Studio 2015. You can use IsWindowsVersionOrGreater in the general case however. For example on my 7 box I get TRUE for IsWindowsVersionOrGreater(6, 0, 0).
Remember that the parameters this function takes relate to Windows build number and NOT marketing name. So Windows 8 is build 6.2. Windows 7 is 6.0 etc.
Use the following function:
double getSysOpType()
{
double ret = 0.0;
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
OSVERSIONINFOEXW osInfo;
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
if (NULL != RtlGetVersion)
{
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
RtlGetVersion(&osInfo);
ret = (double)osInfo.dwMajorVersion;
}
return ret;
}
It will return the Windows version as a double (7, 8, 8.1, 10).
2021-01-12
https://stackoverflow.com/a/52122386/1923561
Based on Michael Haephrati's answer, I made adjustments to my code.
enum WindowsOS{
NotFind,
Win2000,
WinXP,
WinVista,
Win7,
Win8,
Win10
};
WindowsOS GetOsVersionQuick()
{
using namespace std;
double ret = 0.0;
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
OSVERSIONINFOEXW osInfo;
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"),
"RtlGetVersion");
if (NULL != RtlGetVersion)
{
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
RtlGetVersion(&osInfo);
ret = (double)osInfo.dwMajorVersion;
}
if (osInfo.dwMajorVersion == 10 && osInfo.dwMinorVersion == 0)
{
cout << "this is windows 10\n";
return Win10;
}
else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 3)
{
cout << "this is windows 8.1\n";
return Win8;
}
else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 2)
{
cout << "this is windows 8\n";
return Win8;
}
else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 1)
{
cout << "this is windows 7 or Windows Server 2008 R2\n";
return Win7;
}
return NotFind;
}
2020-06-14
#include <iostream>
#include <windows.h>
#pragma comment(lib, "Version.lib" )
BOOL GetOsVersion()
{
wchar_t path[200] = L"C:\\Windows\\System32\\kernel32.dll";
DWORD dwDummy;
DWORD dwFVISize = GetFileVersionInfoSize(path, &dwDummy);
LPBYTE lpVersionInfo = new BYTE[dwFVISize];
if (GetFileVersionInfo(path, 0, dwFVISize, lpVersionInfo) == 0)
{
return FALSE;
}
UINT uLen;
VS_FIXEDFILEINFO* lpFfi;
BOOL bVer = VerQueryValue(lpVersionInfo, L"\\", (LPVOID*)&lpFfi, &uLen);
if (!bVer || uLen == 0)
{
return FALSE;
}
DWORD dwProductVersionMS = lpFfi->dwProductVersionMS;
if (HIWORD(dwProductVersionMS) == 10 && LOWORD(dwProductVersionMS) == 0)
{
cout << "this is windows 10\n";
}
else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 3)
{
cout << "this is windows 8.1\n";
}
else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 2)
{
cout << "this is windows 8\n";
}
else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 1)
{
cout << "this is windows 7 or Windows Server 2008 R2\n";
}
else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 0)
{
cout << "this is windows Vista or Windows Server 2008\n";
}
else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 2)
{
cout << "this is windows Server 2003\n";
}
else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 1)
{
cout << "this is windows Server XP\n";
}
else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 0)
{
cout << "this is windows 2000\n";
}
//else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 90)
//{
// cout << "this is windows Me\n";
//}
//else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 10)
//{
// cout << "this is windows 98\n";
//}
//else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 0)
//{
// cout << "this is windows 95\n";
//}
return TRUE;
}
After testing the code used to detect win10.
I speculate that this api error, IsWindows10OrGreater, is because the wrong FileVersionMS version is set for kernel32.dll. Use ProductVersionMS version query to get it normally.
https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows10orgreater
Hope it could help everyone!
I needed this to work on an older version of the VS compiler, and more over within a Qt framework. Here's how I accomplished that.
Add this file GetWinVersion.h to your Qt project:
#ifndef GETWINVERSION
#define GETWINVERSION
#include <QtGlobal>
#ifdef Q_OS_WIN
#include <windows.h>
#include <stdio.h>
float GetWinVersion()
{
OSVERSIONINFO osvi;
ZeroMemory( &osvi, sizeof(OSVERSIONINFO) );
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
return GetVersionEx( &osvi ) ?
(float)osvi.dwMajorVersion +
((float)osvi.dwMinorVersion/10) :
0.0 ;
}
#endif //Q_OS_WIN
#endif // GETWINVERSION
Add the required linkage in your pro or pri qmake file:
msvc: LIBS += -lKernel32
Implement the helper function like so (note SystemInfo used here is a custom class of mine, but you get the idea...):
#include "GetWinVersion.h"
SystemInfo info;
#ifdef Q_OS_WIN
info.setPlatform( SystemInfo::WINDOWS );
switch(QSysInfo::windowsVersion())
{
case QSysInfo::WV_32s: info.setOsName( L"3.1" ); info.setOsVersion( 3.1 ); break;
case QSysInfo::WV_95: info.setOsName( L"95" ); info.setOsVersion( 4.0 ); break;
case QSysInfo::WV_98: info.setOsName( L"98" ); info.setOsVersion( 4.1 ); break;
case QSysInfo::WV_Me: info.setOsName( L"Me" ); info.setOsVersion( 4.9 ); break;
case QSysInfo::WV_NT: info.setOsName( L"NT" ); info.setOsVersion( 4.0 ); break;
case QSysInfo::WV_2000: info.setOsName( L"2000" ); info.setOsVersion( 5.0 ); break;
case QSysInfo::WV_XP: info.setOsName( L"XP" ); info.setOsVersion( 5.1 ); break;
case QSysInfo::WV_2003: info.setOsName( L"2003" ); info.setOsVersion( 5.2 ); break; // Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition
case QSysInfo::WV_VISTA: info.setOsName( L"Vista" ); info.setOsVersion( 6.0 ); break; // Windows Vista, Windows Server 2008
case QSysInfo::WV_WINDOWS7: info.setOsName( L"7" ); info.setOsVersion( 6.1 ); break; // Windows 7, Windows Server 2008 R2
case QSysInfo::WV_WINDOWS8: info.setOsName( L"8" ); info.setOsVersion( 6.2 ); break; // Windows 8, Windows Server 2012
// These cases are never reached due to Windows api changes
// As of Qt 5.5, this not accounted for by QSysInfo::windowsVersion()
//case QSysInfo::WV_WINDOWS8_1: info.setOsName( L"8.1" ); info.setOsVersion( 6.3 ); break; // Windows 8.1, Windows Server 2012 R2
//case QSysInfo::WV_WINDOWS10: info.setOsName( L"10" ); info.setOsVersion( 10.0 ); break; // Windows 10, Windows Server 2016
default:
// On Windows 8.1 & 10, this will only work when the exe
// contains a manifest which targets the specific OS's
// you wish to detect. Else 6.2 (ie. Win 8.0 is returned)
info.setOsVersion( GetWinVersion() );
if( info.osVersion() == 6.3f ) // Windows 8.1, Windows Server 2012 R2
info.setOsName( L"8.1" );
else if( info.osVersion() == 10.0f ) // Windows 10, Windows Server 2016
info.setOsName( L"10" );
else
info.setOsName( L"UNKNOWN" );
}
info.setOsBits( IsWow64() ? 64 : 32 );
#else
...
Now here's the real key. You need to attach a manifest file to your exe which will "target" the recent Windows versions, else you can't detect them (see the MS docs: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx). Here's an example manifest to do this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="MyOrg.MyDept.MyAppName"
version="1.0.0.0"
processorArchitecture="x86"
type="win32" />
<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 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
</assembly>
And here's some batch to attach the manifest:
set exeFile=MyApp.exe
set manifestFile=MyApp.manifest
set manifestExe=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\x64\mt.exe
"%manifestExe%" -manifest "%manifestFile%" -outputresource:"%exeFile%"
In theory, you can use qmake to run that last bit attaching the manifest. I didn't have luck with the examples I found, and just "cheated" with this batch for now...
Do not use VersionHelpers.h! It's buggy!
It ignores the user's application compatibility settings.
Instead, use the older Kernel32.dll functions like GetVersion, e.g.:
bool IsWindowsVersionOrGreater(unsigned short version)
{
return _byteswap_ushort((unsigned short)GetVersion()) >= version;
}
// Usage: IsWindowsVersionOrGreater(_WIN32_WINNT_WINTHRESHOLD)
FWIW, the LibreOffice project gives the version string via getOSVersion()
OUString WinSalInstance::getOSVersion()
{
OUStringBuffer aVer(50); // capacity for string like "Windows 6.1 Service Pack 1 build 7601"
aVer.append("Windows ");
// GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
// subject to manifest-based behavior since Windows 8.1, so give wrong results.
// Another approach would be to use NetWkstaGetInfo, but that has some small
// reported delays (some milliseconds), and might get slower in domains with
// poor network connections.
// So go with a solution described at https://web.archive.org/web/20090228100958/http://msdn.microsoft.com/en-us/library/ms724429.aspx
bool bHaveVerFromKernel32 = false;
if (HMODULE h_kernel32 = GetModuleHandleW(L"kernel32.dll"))
{
wchar_t szPath[MAX_PATH];
DWORD dwCount = GetModuleFileNameW(h_kernel32, szPath, SAL_N_ELEMENTS(szPath));
if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath))
{
dwCount = GetFileVersionInfoSizeW(szPath, nullptr);
if (dwCount != 0)
{
std::unique_ptr<char[]> ver(new char[dwCount]);
if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE)
{
void* pBlock = nullptr;
UINT dwBlockSz = 0;
if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE && dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
{
VS_FIXEDFILEINFO* vi1 = static_cast<VS_FIXEDFILEINFO*>(pBlock);
aVer.append(OUString::number(HIWORD(vi1->dwProductVersionMS)) + "."
+ OUString::number(LOWORD(vi1->dwProductVersionMS)));
bHaveVerFromKernel32 = true;
}
}
}
}
}
// Now use RtlGetVersion (which is not subject to deprecation for GetVersion(Ex) API)
// to get build number and SP info
bool bHaveVerFromRtlGetVersion = false;
if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
{
if (auto RtlGetVersion
= reinterpret_cast<RtlGetVersion_t>(GetProcAddress(h_ntdll, "RtlGetVersion")))
{
RTL_OSVERSIONINFOW vi2{}; // initialize with zeroes - a better alternative to memset
vi2.dwOSVersionInfoSize = sizeof(vi2);
if (STATUS_SUCCESS == RtlGetVersion(&vi2))
{
if (!bHaveVerFromKernel32) // we failed above; let's hope this would be useful
aVer.append(OUString::number(vi2.dwMajorVersion) + "."
+ OUString::number(vi2.dwMinorVersion));
aVer.append(" ");
if (vi2.szCSDVersion[0])
aVer.append(OUString::Concat(o3tl::toU(vi2.szCSDVersion)) + " ");
aVer.append("Build " + OUString::number(vi2.dwBuildNumber));
bHaveVerFromRtlGetVersion = true;
}
}
}
if (!bHaveVerFromKernel32 && !bHaveVerFromRtlGetVersion)
aVer.append("unknown");
return aVer.makeStringAndClear();
}

nVidia driver version from WMI is not what I want

I want to get driver version of nVidia video card.
So I used WMI and get data from "DriverVersion" obejct of "Win32_VideoController" class.
But it was like "9.18.13.1106"(file version) and what I wanted is something like "311.06"(treiber version).
Where can I get that information?
If it is impossible on WMI, I want to know other way to get that.
Thanks.
You can do this using NVML from nVidia's Tesla Deployment Kit. You can retrieve the internal driver version (the one you're accustomed to seeing for an nVidia driver) with code like this:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <nvml.h>
#include <windows.h>
namespace {
typedef nvmlReturn_t (*init)();
typedef nvmlReturn_t (*shutdown)();
typedef nvmlReturn_t (*get_version)(char *, unsigned);
class NVML {
init nvmlInit;
shutdown nvmlShutdown;
get_version nvmlGetDriverVersion;
std::string find_dll() {
std::string loc(getenv("ProgramW6432"));
loc += "\\Nvidia Corporation\\nvsmi\\nvml.dll";
return loc;
}
public:
NVML() {
HMODULE lib = LoadLibrary(find_dll().c_str());
nvmlInit = (init)GetProcAddress(lib, "nvmlInit");
nvmlShutdown = (shutdown)GetProcAddress(lib, "nvmlShutdown");
nvmlGetDriverVersion = (get_version)GetProcAddress(lib, "nvmlSystemGetDriverVersion");
if (NVML_SUCCESS != nvmlInit())
throw(std::runtime_error("Unable to initialize NVML"));
}
std::string get_ver() {
char buffer[81];
nvmlGetDriverVersion(buffer, sizeof(buffer));
return std::string(buffer);
}
~NVML() {
if (NVML_SUCCESS != nvmlShutdown())
throw(std::runtime_error("Unable to shut down NVML"));
}
};
}
int main() {
std::cout << "nVidia Driver version: " << NVML().get_ver();
}
Note that if you're writing this purely for your own use on a machine where you're free to edit the PATH, you can simplify this quite a bit. Most of the code deals with the fact that this uses NVML.DLL, which is in a directory that's not normally on the path, so the code loads that dynamically, and uses GetProcAddress to find the functions in it that we need to use. In this case, we're only using three functions, so it's not all that difficult to deal with, but it still at drastically increases the length of the code.
If we could ignore all that nonsense, the real code would just come out to something on this general order:
nvmlInit();
nvmlSystemGetDriverVersion(result, sizeof(result));
std::cout << result;
nvmlShutdown();
Anyway, to build it, you'll need a command line something like:
cl -Ic:\tdk\nvml\include nv_driver_version.cpp
...assuming you've installed the Tesla Deployment Kit at c:\tdk.
In any case, yes, I've tested this to at least some degree. On my desktop it prints out:
nVidia Driver version: 314.22
...which matches what I have installed.
To get the Nvidia driver version through C++ on Win64:
Download NVAPI https://developer.nvidia.com/rtx/path-tracing/nvapi/get-started, a few MB
The main folder of the downloaded archive contains several header files, one of which is nvapi.h. Those headers are needed for compilation. The subfolder amd64 contains nvapi64.lib, which is needed for linking. The following code will now show the driver version:
#include <iostream>
extern "C" {
#include "nvapi.h"
}
int main() {
NvAPI_Status status = NVAPI_OK;
NvAPI_ShortString str;
status = NvAPI_Initialize();
if (status == NVAPI_LIBRARY_NOT_FOUND) {
//in this case NvAPI_GetErrorMessage() will only return an empty string
std::printf("error no nvidia driver found\n");
} else if (status != NVAPI_OK) {
NvAPI_GetErrorMessage(status, str);
std::printf("error initializing nvapi: %s\n", str);
}
NvU32 version = 0;
NvAPI_ShortString branch;
status = NvAPI_SYS_GetDriverAndBranchVersion(&version, branch);
if (status != NVAPI_OK) {
NvAPI_GetErrorMessage(status, str);
std::printf("error getting driver version: %s\n", str);
} else {
std::printf("driver version %d.%d", version / 100, version % 100);
}
}