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();
}
Related
getting information if operating system is 32-bit or 64-bit from Qt Framework, to be portable on different OS's
I can get from Qt information wether the application has been build for as 32 or 64-bit (QSysInfo::buildCpuArchitecture()) or wether the CPU is 32 or 64-bit (QSysInfo::currentCpuArchitecture()), the operating system name(QSysInfo::prettyProductName()) but I haven't find how to determine if the operating system is 32 or 64-bit with Qt (should be portable!).
Is there any function in Qt to get that information?
Thanks for your time.
qDebug() << "QSysInfo::buildCpuArchitecture():" << QSysInfo::buildCpuArchitecture();
qDebug() << "QSysInfo::currentCpuArchitecture():" << QSysInfo::currentCpuArchitecture();
qDebug() << "QSysInfo::buildAbi():" << QSysInfo::buildAbi();
qDebug() << "QSysInfo::prettyProductName():" << QSysInfo::prettyProductName();
// the result with MinGW 32-bit:
// QSysInfo::buildCpuArchitecture(): "i386"
// QSysInfo::currentCpuArchitecture(): "x86_64"
// QSysInfo::buildAbi(): "i386-little_endian-ilp32"
// QSysInfo::prettyProductName(): "Windows 10"
// the result with VC++ 64-bit:
// QSysInfo::buildCpuArchitecture(): "x86_64"
// QSysInfo::currentCpuArchitecture(): "x86_64"
// QSysInfo::buildAbi(): "x86_64-little_endian-llp64"
// QSysInfo::prettyProductName(): "Windows 10"
Although the name suggests otherwise, currentCpuArchitecture does not tell you whether the CPU is 32bit or 64bit, but will tell you about the bitness of the operating system.
QString QSysInfo::currentCpuArchitecture()
Returns the architecture of the CPU that the application is running
on, in text format. Note that this function depends on what the OS
will report and may not detect the actual CPU architecture if the OS
hides that information or is unable to provide it. For example, a
32-bit OS running on a 64-bit CPU is usually unable to determine the
CPU is actually capable of running 64-bit programs.
http://doc.qt.io/qt-5/qsysinfo.html#currentCpuArchitecture
After many trials, I have found a solution, which gives also the right result with a 32-bit application an 64-bit Windows:
#if defined(Q_OS_WIN)
inline bool isWow64Process()
{
// https://learn.microsoft.com/en-us/windows/desktop/api/wow64apiset/nf-wow64apiset-iswow64process
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
BOOL bIsWow64 = FALSE;
//IsWow64Process is not available on all supported versions of Windows.
//Use GetModuleHandle to get a handle to the DLL that contains the function
//and GetProcAddress to get a pointer to the function if available.
LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
if( NULL != fnIsWow64Process )
{
if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
{
// we couldn't get the pointer to the function,
// we assume that app is not running as
// WOW64 process and return therefore FALSE
bIsWow64 = FALSE;
}
}
return bIsWow64;
}
#endif // (_MSC_VER)
QString osInfo()
{
#if defined(Q_OS_WIN)
QString osBitness( QSysInfo::buildAbi().contains("ilp32") && !isWow64Process()? "32-bit" : "64-bit" );
return QString( QSysInfo::prettyProductName() + " - " + osBitness);
#else // we do not know how to get OS bitness on Linux and OS-X (we do not mean processor, neither application, but OS!)
return QSysInfo::prettyProductName();
#endif
}
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.
Running the following example for _stat from MSDN compiled with Visual C++ 2015 Express using v140_xp as Platform Toolset (target Win32) runs normally on Windows 7 but not on Windows XP on several machines I tested.
// crt_stat.c
// This program uses the _stat function to
// report information about the file named crt_stat.c.
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
int main()
{
struct _stat buf;
int result;
char timebuf[26];
char* filename = "crt_stat.c"; // Absolute paths like "D:\\crt_stat.c" produce the same behaviour.
errno_t err;
// Get data associated with "crt_stat.c":
result = _stat( filename, &buf );
// Check if statistics are valid:
if ( result != 0 )
{
perror( "Problem getting information" );
switch ( errno )
{
case ENOENT:
printf( "File %s not found.\n", filename );
break;
case EINVAL:
printf( "Invalid parameter to _stat.\n" );
break;
default:
/* Should never be reached. */
printf( "Unexpected error in _stat.\n" );
}
}
else
{
// Output some of the statistics:
printf( "File size : %ld\n", buf.st_size );
printf( "Drive : %c:\n", buf.st_dev + 'A' );
err = ctime_s( timebuf, 26, &buf.st_mtime );
if ( err )
{
printf( "Invalid arguments to ctime_s." );
return 1;
}
printf( "Time modified : %s", timebuf );
}
}
Windows 7 output:
File size : 6
Drive : D:
Time modified : Tue Sep 8 10:06:57 2015
Windows XP output:
Problem getting information: Invalid argument
Invalid parameter to _stat.
And yes crt_stat.c is located in the executables directory which also is the CWD.
Is this a Bug or am I missing something?
As pointed out in the comments, it is a bug in the runtime. Right now (2015-09-09) the fix is not yet available in an update, but probably will be soon. A workaround is to use GetFileAttributesEx instead.
The bug is solved on Visual C++ Redistributable for Visual Studio 2015 Update 1
I solved the problem by installing that update form here: https://www.microsoft.com/en-us/download/details.aspx?id=49984
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.
I have the following application, to check installed programs in a system:
#include <iostream>
#include <Msi.h>
#include <Windows.h>
using namespace std;
void main()
{
UINT ret;
DWORD dwIndex = 0;
DWORD dwContext = MSIINSTALLCONTEXT_ALL;
char szInstalledProductCode[39] = {0};
char szSid[128] = {0};
const char* szUserSid = "s-1-1-0";
DWORD cchSid;
MSIINSTALLCONTEXT dwInstalledContext;
do
{
memset(szInstalledProductCode, 0, sizeof(szInstalledProductCode));
cchSid = sizeof(szSid)/sizeof(szSid[0]);
ret = MsiEnumProductsEx(
NULL, // all the products in the context
szUserSid, // i.e.Everyone, all users in the system
dwContext,
dwIndex,
szInstalledProductCode,
&dwInstalledContext,
szSid,
&cchSid
);
if(ret == ERROR_SUCCESS)
{
char* name = MsiGetProductInfoEx (
szInstalledProductCode,
cchSid == 0 ? NULL : szSid,
dwInstalledContext,
INSTALLPROPERTY_INSTALLEDPRODUCTNAME
);
char* version = MsiGetProductInfoEx (
szInstalledProductCode,
cchSid == 0 ? NULL : szSid,
dwInstalledContext,
INSTALLPROPERTY_VERSIONSTRING
);
cout << name << endl;
cout << " - " << version << endl;
dwIndex++;
}
} while(ret == ERROR_SUCCESS);
}
I am using Microsoft Visual C++ Express 2010. The application is MBCS. In studio, these four things are in red (error):
MSIINSTALLCONTEXT_ALL
MSIINSTALLCONTEXT
MsiEnumProductsEx
MsiGetProductInfoEx
I linked the Msi.lib (Project properties -> Linker -> Input -> Additional Dependencies). I am just trying to figure out how MsiEnumProductsEx function works. I know there are other questions around, but I just can't understand why it isn't working because I think that I have everything for the functions to be available, at least. Thanks!
The MSIINSTALLCONTEXT_ALL (and related identifiers) are defined in <msi.h> only if _WIN32_MSI >= 300. You have to tell the Windows SDK what the minimum OS version you're targeting is, by defining a few macros before installing any SDK headers (like <msi.h> or <windows.h>).
You do that according to this MSDN page.
Once you've defined a suitable minimum version (looks like Windows XP SP2 and up), then _WIN32_MSI will be set to an appropriate level, and you should get the symbols.