Need a function to get windows OS name and version [duplicate] - c++

I am trying to find the build version of Windows Server 2016 machines, for example RS1 or RS3. There was an API to do this - GetVersionEx() - but is now deprecated.
MSDN says to use Version Helper Functions instead.
I want the build version, for ex: 1607 for RS1.
Is there an API to get this?

Option 0: (per RbMm) Use [RtlGetVersion] from the driver development kit.
Option 1: [Updated] Grab the version number of a system DLL like kernel32.dll. MSDN used to bless this approach, saying:
To obtain the full version number for the operating system, call the GetFileVersionInfo function on one of the system DLLs, such as Kernel32.dll, then call VerQueryValue to obtain the \StringFileInfo\\ProductVersion subblock of the file version information. [From an Internet Archive snapshot of MSDN circa 2017]
That would look something like this:
// Quick hack without error checking.
#include <cassert>
#include <iomanip>
#include <iostream>
#include <vector>
#include <Windows.h>
int main() {
const auto system = L"kernel32.dll";
DWORD dummy;
const auto cbInfo =
::GetFileVersionInfoSizeExW(FILE_VER_GET_NEUTRAL, system, &dummy);
std::vector<char> buffer(cbInfo);
::GetFileVersionInfoExW(FILE_VER_GET_NEUTRAL, system, dummy,
buffer.size(), &buffer[0]);
void *p = nullptr;
UINT size = 0;
::VerQueryValueW(buffer.data(), L"\\", &p, &size);
assert(size >= sizeof(VS_FIXEDFILEINFO));
assert(p != nullptr);
auto pFixed = static_cast<const VS_FIXEDFILEINFO *>(p);
std::cout << HIWORD(pFixed->dwFileVersionMS) << '.'
<< LOWORD(pFixed->dwFileVersionMS) << '.'
<< HIWORD(pFixed->dwFileVersionLS) << '.'
<< LOWORD(pFixed->dwFileVersionLS) << '\n';
return 0;
}
Note that the original MSDN link now redirects to a newer documentation set that doesn't mention this approach. I suppose that means this is no longer a supported technique, and, presumably, all the compatibility hacks for older code might prevent an application from getting the actual answer.
Option 2: Query the registry, specifically:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
which has values for CurrentMajorVersionNumber, CurrentMinorVersionNumber, and CurrentBuildNumber.
I can't find official documentation for these values, so this may not be MSDN-approved or future-proof.
Option 3: Use GetProductInfo if available and fall back to GetVersionInfo if it's not.

Related

CFLocaleCopyCurrent stale value

At my workplace, our app determines the locale of the user session by using a code that is similar to below (though there are various layers of code it passes through before it reaches here at the time of startup, so the problem is/may not evident by running the code below)
#include <CoreFoundation/CoreFoundation.h>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// Reference release
struct reference_close
{
void operator()(const void *ref) const
{
CFRelease(static_cast<CFTypeRef>(ref));
}
}; // end of reference_close structure
typedef std::unique_ptr<const void, reference_close> reference_uptr;
std::string get_user_locale()
{
reference_uptr ref_ptr(CFLocaleCopyCurrent());
CFLocaleRef locale_ref(static_cast<CFLocaleRef>(ref_ptr.get()));
if (locale_ref == nullptr)
{
return std::string();
}
const size_t default_size(128);
std::vector<char> buff(default_size);
CFStringRef str_ref(CFLocaleGetIdentifier(locale_ref));
if (str_ref != nullptr)
{
CFIndex len(CFStringGetLength(str_ref) + 1);
if (len > boost::numeric_cast<CFIndex>(default_size))
{
buff.resize(len);
}
buff[0] = 0;
if (!CFStringGetCString(str_ref, &buff[0], len, kCFStringEncodingISOLatin1))
{
return std::string();
}
}
return std::string(&buff[0]);
} // end of get_user_locale()
int main()
{
std::cout << "get_user_locale() : "<<get_user_locale() << std::endl;
return 0;
}
The app has a well defined bundle structure with necessary resources and localization resource directories e.g Contents/Resources/ja.lproj
Lately, we are facing an issue wherein we do the following
1) Change the system language and country in the preferences e.g. change from en_US to ja_JP
2) Reboot the machine
3) Launch the app and see the erroneous output e.g en_JP
4) Re-launch the app to get the correct answer as ja_JP
I have read the documentation of CFLocaleCopyCurrent which states that
Settings you get from this locale do not change as a user's
preferences are changed so that your operations are consistent.
Typically you perform some operations on the returned object and then
release it. Since the returned object may be cached, you do not need
to hold on to it indefinitely.
I also checked the another documentation on lifetime of CFLocale which states that
The object you get back from CFLocaleCopyCurrent does not change when
the user changes their Preferences settings. Moreover, the object
itself may be cached by the runtime system, so successive calls of
CFLocaleCopyCurrent may return the same object, even if a user has
changed preference settings. If you want to ensure that your locale
settings are consistent with user preferences, you must synchronize
preferences and get a new locale object with CFLocaleCopyCurrent.
Given this info, I tried to incorporate CFPreferencesSynchronize and/or CFPreferencesSynchronize in the app code (just before I call the CFLocaleCopyCurrent) to get the most updated locale. But no luck.
Do I need to do anything extra to make sure that I get the most recent/updated value of locale object from the system preferences ?
Use [NSLocale autoupdatingCurrentLocale] which will change as the user changes their locale settings, but as NSLocale is an Objective-C class you will need to implement glue code as Objective-C++.
Here is some untested example code, giving you the idea:
Create a file called AppleLocale.mm (unless of course your project is for Apple platforms only so doesn't need the Apple name prefix).
#include <Foundation/Foundation.h>
std::string get_user_locale()
{
NSLocale* locale = [NSLocale autoupdatingCurrentLocale];
return std::string([[locale localeIdentifier] UTF8String]);
}
Note: You'll need a function prototype in some header as well, of course.

Detecting Windows 10 version

My objective is to detect Windows 10 in my code which has to work cross-platform as well as across different versions of Windows (atleast 7 & up). Windows provides IsWindows10OrGreater() to tackle this problem, but there's another issue with it, this function isn't present in previous windows versions.
You'll find countless blogs and SO questions regarding this as well as the manifest madness where functions like this and getversion and others return some different version rather than the correct one.
For example on my machine - the method IsWindows10OrGreater() doesn't compile(I would've to install Win10 SDK), and IsWindowsVersionOrGreater() reports 6 as major version.
So is there a sane multi-version way I could solve this problem?
The most straight-forward way to retrieve the true OS version is to call RtlGetVersion. It is what GetVersionEx and VerifyVersionInfo call, but doesn't employ the compatibility shims.
You can either use the DDK (by #including <ntddk.h> and linking against NtosKrnl.lib from kernel mode, or ntdll.lib from user mode), or use runtime dynamic linking as in the following snippet:
typedef LONG NTSTATUS, *PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)
typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RTL_OSVERSIONINFOW GetRealOSVersion() {
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
if (hMod) {
RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
if (fxPtr != nullptr) {
RTL_OSVERSIONINFOW rovi = { 0 };
rovi.dwOSVersionInfoSize = sizeof(rovi);
if ( STATUS_SUCCESS == fxPtr(&rovi) ) {
return rovi;
}
}
}
RTL_OSVERSIONINFOW rovi = { 0 };
return rovi;
}
In case you need additional information you can pass an RTL_OSVERSIONINFOEXW structure in place of the RTL_OSVERSIONINFOW structure (properly assigning the dwOSVersionInfoSize member).
This returns the expected result on Windows 10, even when there is no manifest attached.
As an aside, it is commonly accepted as a better solution to provide different implementations based on available features rather than OS versions.
You can read real build number from the registry, and then infer Windows version from it. Your application does not need to have a manifest for this work: on my machine, it correctly detects OS build number as 10586. For example:
#include <Windows.h>
#include <sstream>
struct HKeyHolder
{
private:
HKEY m_Key;
public:
HKeyHolder() :
m_Key(nullptr)
{
}
HKeyHolder(const HKeyHolder&) = delete;
HKeyHolder& operator=(const HKeyHolder&) = delete;
~HKeyHolder()
{
if (m_Key != nullptr)
RegCloseKey(m_Key);
}
operator HKEY() const
{
return m_Key;
}
HKEY* operator&()
{
return &m_Key;
}
};
bool IsRunningOnWindows10()
{
HKeyHolder currentVersion;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, KEY_QUERY_VALUE, &currentVersion) != ERROR_SUCCESS)
return false;
DWORD valueType;
BYTE buffer[256];
DWORD bufferSize = 256;
if (RegQueryValueExW(currentVersion, L"CurrentBuild", nullptr, &valueType, buffer, &bufferSize) != ERROR_SUCCESS)
return false;
if (valueType != REG_SZ)
return false;
int version;
std::wistringstream versionStream(reinterpret_cast<wchar_t*>(buffer));
versionStream >> version;
return version > 9800;
}
IsWindows10OrGreater() from VersionHelpers.h
Check the notes at Version Helper functions on MSDN
File VersionHelpers.h is shipped with Windows 10 SDK, but it will work in previous versions, too. Just copy it to your development environment.
It's just a header-only defined small lib, which uses VerSetConditionMask and VerifyVersionInfoW functions, both available in WinAPI since Windows 2000.
Upd If you can not include manifest file with your source code, you can use simple hack: just get a version of any system dll, for example, kernel32.dll using GetFileVersionInfo function.

GetEnvironmentVariableA() usage

I am working on a C++ Console Application in Visual Studio 2012 on Windows 7 and I want to get the values of some environment variables from within the application.
Here is what I've tried so far -:
int main()
{
char a[1000];
int s=GetEnvironmentVariableA("HOME",a,1000);
}
However, I am getting the value of s to be 0, indicating that variable "HOME" does not exist.
Also, getenv("HOME") returns NULL too.
So, what is the correct procedure of doing this ?
What this program is telling you, most likely, is that your process environment does not contain a variable named HOME. Note that HOME is not a variable that you would expect to be defined, unless you have taken steps to define it. Either by adding it to the system's environment, or by specifying a bespoke environment when creating the process.
The documentation says the following about the return value:
If the function succeeds, the return value is the number of characters
stored in the buffer pointed to by lpBuffer, not including the
terminating null character.
If lpBuffer is not large enough to hold the data, the return value is
the buffer size, in characters, required to hold the string and its
terminating null character and the contents of lpBuffer are undefined.
If the function fails, the return value is zero. If the specified
environment variable was not found in the environment block,
GetLastError returns ERROR_ENVVAR_NOT_FOUND.
So, if the function returns 0, do as the documentation says. Call GetLastError to find out why the function call failed.
But as I said, with probability very close to 1, the reason will simply be that your process environment has not defined a variable named HOME.
As to how you move forward, most likely you are looking for a location in the user's profile. Exactly how you do this will depend on where in the profile you wish to store/load the file. One of the APIs related to CSIDL or known folder IDs will serve your needs.
Regarding your question,
” So, what is the correct procedure of doing this ?
Windows doesn't have a single HOME standard variable. Instead, in the old days there were HOMEDRIVE and HOMEPATH, and apparently because they didn't know about it, with Windows Explorer in Windows 95, a new variable called USERPROFILE.
[C:\Users\alfps_000]
> set home
HOMEDRIVE=C:
HOMEPATH=\Users\alfps_000
[C:\Users\alfps_000]
> set user
USERDOMAIN=FRIKADELL
USERDOMAIN_ROAMINGPROFILE=FRIKADELL
USERNAME=alfps_000
USERPROFILE=C:\Users\alfps_000
[C:\Users\alfps_000]
> _
The silly triple-oh suffix (as if I were better than double-oh seven) is just what Windows 8.1 saw fit to give me. It's just too much work to cajole Windows into reasonable choices. And so not just with usernames but also with environment variables.
Here's your program rewritten to use the Windows variable that vaguely corresponds to Unix-land HOME, namely USERPROFILE:
#include <iostream>
#include <stdlib.h> // getenv
using namespace std;
auto main() -> int
{
cout
<< "User's profile directory: "
<< "[" << getenv( "USERPROFILE" ) << "]"
<< endl;
}
The Windows environment variables are awkward and not guaranteed, but still usable in scripts and very simple programs like the one above. In more serious C++ code you can instead use the SHGetKnownFolderPath API function. With Visual C++ it can look like this:
#undef UNICODE
#define UNICODE
#include <windows.h>
#include <shlobj.h> // SHGetKnownFolderPath
#include <objbase.h> // CoTaskMemFree
#include <iostream> // std::wcout
#include <memory> // std::unique_ptr
#include <stdexcept> // std::runtime_error, std::exception
#include <stdlib.h> // EXIT_FALURE, EXIT_SUCCESS
using namespace std;
void cotaskmem_free( wchar_t* p ) { CoTaskMemFree( p ); }
auto main() -> int
{
using X = runtime_error;
using String_deallocation = unique_ptr<wchar_t[], void(*)(wchar_t*)>;
try
{
wchar_t* path;
HRESULT const hr = SHGetKnownFolderPath(
FOLDERID_Profile, // REFKNOWNFOLDERID rfid -> %USERPROFILE%
0, // DWORD dwFlags,
0, // HANDLE hToken,
&path // PWSTR *ppszPath
);
if( FAILED( hr ) ) { throw X( "SHGetKnownFolderPath failed" ); }
String_deallocation const path_cleanup( path, cotaskmem_free );
wcout << "User profile directory: [" << path << "]" << endl;
return EXIT_SUCCESS;
}
catch( exception const& x )
{
wcerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
g++ (per version 4.8.2) doesn't yet support API functions from Windows Vista and onward, at least not in general, so if you need to support g++ use some older function.
Note:
It's not unlikely that whatever you intended to access or place in %HOME%, would better be accessed or placed in one of the other special users's directories, also available via SHGetKnownFolderPath.

Segmentation fault when creating custom tcl channel driver

I am trying to create custom tcl channel and use it to get the output of tcl Interpreter. I added the implementation of few function of Tcl_ChannelType but I am getting segfault.
#include <tcl.h>
#include <iostream>
int driverBlockModeProc(ClientData instanceData, int mode) {
std::cout << "driverBlockModeProc\n";
return 0;
}
int driverCloseProc(ClientData instanceData, Tcl_Interp *interp) {
std::cout << "driverCloseProc\n";
return 0;
}
int driverInputProc(ClientData instanceData, char* buf, int bufSize, int *errorCodePtr) {
std::cout << "driverInputProc\n";
return 0;
}
int driverOutputProc(ClientData instanceData, const char* buf, int toWrite, int *errorCodePtr) {
std::cout << "driverOutputProc\n";
return 0;
}
int main() {
Tcl_ChannelType *typePtr = new Tcl_ChannelType;
typePtr->blockModeProc = driverBlockModeProc;
typePtr->outputProc = driverOutputProc;
typePtr->closeProc = driverCloseProc;
typePtr->inputProc = driverInputProc;
typePtr->seekProc = NULL;
typePtr->setOptionProc = NULL;
typePtr->getOptionProc = NULL;
typePtr->watchProc = NULL;
typePtr->getHandleProc = NULL;
typePtr->close2Proc = NULL;
typePtr->blockModeProc = NULL;
typePtr->flushProc = NULL;
typePtr->handlerProc = NULL;
typePtr->wideSeekProc = NULL;
typePtr->threadActionProc = NULL;
ClientData data = new char[200];
Tcl_CreateChannel(typePtr, "im_chanel", data, TCL_WRITABLE | TCL_READABLE);
}
I cant debug the segfault because its source are not available. I think the segfault is because a function is called which is NULL. I only need to use the channel to get the output of interpreter. Which functions I needn't implement here and is it right direction to solve the problem.
You're advised to download the source to Tcl when working at this level. I'm not sure what version you're using, but all official distributions of the source going back a very long way are on the SourceForge file distribution system; pick the exact match for the version you've got.
Creating a custom channel driver is not easy. There's a significant amount of complexity involved, and it isn't especially well-documented what “methods” within the channel driver type are mandatory and what are optional. (They're not C++ methods in a class — Tcl is pure C code for reasons too long to go into here — but they function in a conceptually similar way.)
If we look at the documentation for Tcl_CreateChannel, we see (quite a long way down that page) a definition of the channel type structure. The channel type structure should be statically allocated (Tcl's implementation assumes very strongly that it never changes location) and the following fields must be set to something meaningful:
typeName — This is the name of the channel type, useful for debugging!
version — This is the version of the channel type; you should set it to the latest version supported by your target source level. (You're recommended to use at least TCL_CHANNEL_VERSION_2 or things get rather more complex.)
closeProc or close2Proc — Channels must be closeable, but you have two choices for ways to do it. Bidirectional channels ought to use the close2Proc, but aren't strictly required to.
inputProc — Only needed if you're reading; take care to handle this correctly.
outputProc — Only needed if you're writing; take care to handle this correctly.
watchProc — Called to tell the channel driver to install itself into the event system so as to receive suitable events (as instructed by the supplied bitmask). Channels that don't have backing OS handles use timer events, or simply never actually generate events (in which case they'll never become readable or writable from the perspective of fileevent).
Looking at your code, I see that you're missing a watchProc. I know it's hard to see (not many people write channel drivers, to be honest, so the documentation isn't very hard “tested”) but it's really necessary.

Multiplatform way to determine if a dynamic library is present

I need to check if a dynamic library is present, so that later I can safely call functions that use this library.
Is there a multiplatform way to check this? I am targeting MS Windows 7 (VC++11) and Linux (g++).
To dynamically "use" a function from a shared library requires that the library isn't part of the executable file, so you will need to write code to load the library and then use the function. There may well be ways to to do that in a portable fashion, but I'm not aware of any code available to do that.
It isn't very hard code to write. As "steps", it involves the following:
Load the library given a name of a file (e.g. "xx", which is then translated to "xx.so" or "xx.dll" in the architecture specific code).
Find a function based on either index ("function number 1") or name ("function blah"), and return the address.
Repeat step 2 for all relevant functions.
When no longer needing the library, close it with the handle provided.
If step 1 fails, then your library isn't present (or otherwise "not going to work"), so you can't call functions in it...
Clearly, there are many ways to design an interface to provide this type of functionality, and exactly how you go about that would depend on what your actual problem setting is.
Edit:
To clarify the difference between using a DLL directly, and using one using dynamic loading from the code:
Imagine that this is our "shared.h", which defines the functions for the shared library
(There is probably some declspec(...) or exportsymbol or other such stuff in a real header, but I'll completely ignore that for now).
int func1();
char *func2(int x);
In a piece of code that directly uses the DLL, you'd just do:
#include <shared.h>
int main()
{
int x = func1();
char *str = func2(42);
cout << "x=" << x << " str=" << str << endl;
return 0;
}
Pretty straight forward, right?
When we use a shared library that is dynamically loaded by the code, it gets a fair bit more complex:
#include <shared.h>
typedef int (*ptrfunc1)();
typedef char * (*ptrfunc2)(int x);
int main()
{
SOMETYPE handle = loadlibrary("shared");
if (handle == ERROR_INDICATOR)
{
cerr << "Error: Couldn't load shared library 'shared'";
return 1;
}
ptrfunc1 pf1 = reinterpret_cast<ptrfunc1>(findfunc("func1"));
ptrfunc2 pf2 = reinterpret_cast<ptrfunc2>(findfunc("func2"));
int x = pf1();
char *str = pf2(42);
cout << "x=" << x << " str=" << str << endl;
return 0;
}
As you can see, the code suddenly got a lot more "messy". Never mind what hoops you have to jump through to find the constructor for a QObject, or worse, inherit from a QObject. In other words, if you are using Qt in your code, you are probably stuck with linking directly to "qt.lib" and your application WILL crash if a Qt environment isn't installed on the machine.
LoadLibrary calls should fail, then you can know if the dynamic library is present or not. Also with dynamic loading you get the function pointer from the dynamic library and if the pointer is null then the platform doesn't support that function on that platform.
On windows you have LoadLibrary API to load a dynamic lib. And GetProcAddress API to look up the desired function in that lib. If GetProcAddress returns NULL for that particular function that you are looking for that functionality is not present for that platform. You can log then and decide fallback.