OS Name: Windows 10
Service Pack ver.: 0
Is Server? False
Bitness: x64
Is Win x64: True
Is Win x32: False
Edition: Pro
Suite mask: SingleUserTS
ProductType: Workstation
PlatformID: 2 (WinNT)
Is Domain controller: False
Is Embedded: False
OS - XP/Server 2003(R2)? False
OS - Vista/Server 2008? False
OS - 7/Server 2008R2? False
OS - 8/Server 2012? False
OS - 8.1/Server 2012R2? True
OS - 10/Server 2016? True
OS - XP or newer? True
OS - XP SP3 or newer? True
OS - Vista or newer? True
OS - 7 or newer? True
OS - 8 or newer? True
OS - 8.1 or newer? True
OS - 10 or newer? True
OS - 11 or newer? False
Major: 10
Minor: 0
Major + Minor: 10
Major + Minor (NtDll): 10
Build: 19045
NT Dll Major.Minor.Rev: 10.0.2661
Revision: 3570
ReleaseId: 2009
DisplayVersion: 22H2
Language in dialogues: 1049 RU Russian
Language of OS inslallation: 1049 RU Russian
Language for non-Unicode programs: 1049 RU Russian
ID of default locale: 8192
Process integrity level: Medium
Elevated process? False
Is Local system context? False
User name: admin
User group: Administrators
Is in Admin group? True
User sid of current process owner: S-1-5-21-2880098541-1527459233-1868265087-1001
Computer name: DESKTOP-QHB2VSF
Safe boot? False (Normal)
Secure Boot supported? False (Enabled? False)
TestSigning: False
DebugMode: False
CodeIntegrity: False
File System Case sensitive? False
OEM Codepage: 866 (c_866.nls)
ANSI Codepage: 1251 (c_1251.nls)
Memory MiB (Free/Total): 2928/7167 (Loaded: 59%)
CPU usage: 3,7%
Requirements:
To get reliable result you have to add application manifest with compatibility section. Details are available here.
Manifest is already included in the example attached.
Compatibility
Windows 2000 - 11 (client and server) / Compiled and IDE mode (VB6).
x64 VBA / x64 twinBasic compatibility added (thanks to fafalone). For the most recent x64 IDE version, refer to: https://github.com/fafalone/OSInfo
Last edited by Dragokas; Oct 23rd, 2023 at 11:40 AM.
Reason: new version
Interestingly, it seems to circumvent any compatibility shims when running compiled. However, it doesn't circumvent the shims when executing from the IDE. In other words, if you have compatibility shims set for the VB6.EXE, it'll report whatever those shims say rather than the true OS. When executing from the IDE, here's what I get (and that reflects the shims I have set):
However, when executing a compiled OSverInfo.exe, here's what I get, regardless of what shims are set:
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Added new properties:
- MajorMinorNTDLL (single, RtlGetNtVersionNumbers)
- NtDllVersion (string, the same, but in format Major.Minor.Build)
- Revision
- IsWindowsXPOrGreater
- IsWindowsVistaOrGreater (renamed from old IsVistaOrLater)
- IsWindows7OrGreater
- IsWindows8OrGreater
- IsWindows8Point1OrGreater
- IsWindows10OrGreater
- ReleaseId
- IsServer
- IsWin64
- PlatformID (Win32S = 0, Win32Windows = 1, Win32NT = 2, WinCE = 3)
- SecureBoot (boolean, if Secure Boot is enabled)
Added the list of versions and service packs in code comment.
Updated the list of SuiteMasks.
Detailed information for Win NT 4.0 and Win95 (however, I have no opprotunity to test class on such systems).
I don't think this is a good idea for my concrete class.
It will be much more convenient and understandable for code readability to store env. variables in some separate class, like:
Code:
set Env = new clsEnvVariables
debug.? Env.UserName
Besides, this class was intended for OS version info only.
It's my fault that I allowed myself to expand it to process specific info e.t.c.
Personally, I am using public variables in my programs, but I think with a class it will be much faster to write env. var. names with help of IntelliSense, especially if forgot how to spell the name correctly.
Maybe, further I'll public such class, if I don't find a similar solution in codebank.
Also, the "Environ Function" is pretty easy to use.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Can you explain what the purpose/need is for the initializing in your sample form?
Code:
Private Sub Form_Initialize()
Dim ICC As tagINITCOMMONCONTROLSEX
With ICC
.dwSize = Len(ICC)
.dwICC = ICC_STANDARD_CLASSES 'http://www.geoffchappell.com/studies/windows/shell/comctl32/api/commctrl/initcommoncontrolsex.htm
End With
InitCommonControlsEx ICC
End Sub
Hi, Jimboat.
It is not relevant to the class. It's leftovers for my common manifest. You can safely remove it.
However, if you plan to remove InitCommonControlsEx, you also need to remove <dependency> section in manifest.
Hi, Jimboat.
It is not relevant to the class. It's leftovers for my common manifest. You can safely remove it.
However, if you plan to remove InitCommonControlsEx, you also need to remove <dependency> section in manifest.
Hi, Jimboat.
It is not relevant to the class. It's leftovers for my common manifest. You can safely remove it.
However, if you plan to remove InitCommonControlsEx, you also need to remove <dependency> section in manifest.
Thanks for the feedback.
OK....now i'm interested. What does 'InitCommonControlsEx' do?
Hi, georgekar! Re-download new version. I forgot to upload.
1.7.
Fixed issue, os name doesn't show for domain controller.
1 CloseHandle is missing.
Removed 'SetCurrentProcessPrivileges' as not needed.
Added properties:
- IsDomainController
- IsLocalSystemContext
Please, don't quote the whole post. You are confusing me. I thought that quoted part was your specification.
Which one is real? Those can happen due to hijacked info in the registry or due to some kind of virtualization.
Added detection of:
- Windows 11
- Windows Server 2019
- Windows Server 2022
New properties added:
- IsWin32
- DisplayVersion 'e.g. 21H1
- IsWindowsXP_SP3OrGreater
- UserName
- ComputerName
- IsAdminGroup
- IsSystemCaseSensitive
- IsEmbedded
- LCID_UserDefault
- IsWow64 -> made public.
Other:
- UserType naming corrected: Administrator -> Administrators, Power User -> Power Users, Limited User -> Limited Users, Guest -> Guests.
- All internal functions made private.
- List of Windows product names are updated.
Improved Secure Boot state check.
List of integrity levels appended with:
- Medium Plus
- Secure Process
Appended list of Windows Editions.
Added new properties:
- IsWindows2000
- IsWindowsXP
- IsWindowsVista
- IsWindows7
- IsWindows8
- IsWindows8Point1
- IsWindows10
- IsWindows11OrGreater
- SecureBootSupported
- TestSigning
- DebugMode
- CodeIntegrity
- MemoryTotal
- MemoryFree
- MemoryLoad
- CpuUsage
- CurrentProcessId
*Note: all new IsWin* properties means exact match, however includes Server version as well. You may need additional check (Not .IsServer)
Very useful; do you mind if I make a 64bit port for twinBASIC? (Would of course preserve all credit information)
Also, small error in IsProcessElevated:
Code:
ErrorHandler:
ErrorMsg Now, "clsOSver.IsProcessElevated"
If hToken Then CloseHandle hToken: hToken = 0
End Function
Presumably Now should be Err like all the others; VB6 gives an Object Required error on it when modified to run the handler. You'd likely never run into that in VB where it's a runtime error, but I opened the project in tB and it's flagged as an error in design time.
fafalone, sure.
You can make port or (in case it will be backward-compatible with VB6, e.g. with #Conditional options) you can freely post it here and I'll include it in my primary project, so the next updates will be more simple.
Thanks for pointing me "Err" misprint.
Sure I can post it here. I'll keep the 64bit parts compatible with VBA64 too, that way it'll be usable across the entire VB/tB spectrum. I've already done the hardest part, the legwork of 64bit-compat API declares/UDTs, for my tbShellLib project (only had 4 in this project not yet in it), so shouldn't take too long.
I've attached an updated version. Verified it produces the same info under x64, and verified it still works normally in VB6. So it's now universally compatible with VB6, VBA6, VBA7 32bit, VBA7 64bit, twinBASIC 32bit, and twinBASIC 64bit.
I slightly modified the 'is 64bit' logic to account for no longer being able to rely on always being an x86 process, and replaced the GetMem4/GetMem8 calls with CopyMemory, because those aren't supported in VBA64. (tB *does* support them-- they're redirected to internal implementations, but why not add VBA compat while working on it?). Other than that no changes, just a straight x64 support update.
There's a .twinproj file for twinBASIC included; I'll be putting that on my GitHub later. Note that it will require Beta 412 or newer (released today) when used in tB, due to a bug identified and fixed during the process of updating this.
---
Again, very nice work on the class.
Last edited by fafalone; Oct 20th, 2023 at 01:35 PM.
fafalone, cool. Thank you. Looks good. Not the most simple update considering I used few non-trivial reg query prototypes, with byval string etc, I don't usually using anymore.
I updated first post.
Also:
- removed debugging
- added mem release for perf counters
- moved usage example of cpu usage under a timer, because it is incorrectly to measure it instantly at OSInfo class instantiation. Several ticks should be passed at least to give counters chance to collect usage statistics.
---
P.S. Not production ready yet. Found write outside the buffer in
Actually, I've no idea why GetTokenInformation returns that large amount of buffer required.
For me in VB6 IDE in Win7x64, BufferSize of TOKEN_GROUPS requested == 416, when tpTokens.GroupCount == 17, which is too large even for x64. sizeof(SID_AND_ATTRIBUTES) * 17 == 272 +8 (DWORD +align) = 280 for x64, and == 136 + 8 = 144 for x32. (144 < 416)
It seems it's better to alloc buffer dynamically here.
However, how should I alloc it, according to the number of tpTokens.GroupCount returned or according to the BufferSize returned? ...
--
P.S. All right, I understand this buffer in its tail also contains the data (sid strings) associated with sid pointers. That's why required buff size is larger.
Last edited by Dragokas; Oct 21st, 2023 at 01:51 PM.
There's negligible performance penalty for oversizing the buffer a bit. I only had 15 token groups, but when you're not dynamically allocating it, you want to account for others potentially having more. Like when I do the same for paths, I always go ahead and allocate MAX_PATH. I considered rewriting it to allocate dynamically, but due to the x64 differences and general complexity, figured it wouldn't be worth going there absent a bug report pointing to necessity.
Massively oversizing the buffer was why I didn't think to limit it for a rare scenario where it would overwrite; using LenB(tpTokens) could overread the buffer. So picked one without a redesign.
One other thing I was looking at doing but ultimately didn't was rewriting to avoid the need for a manifest. The version numbers are easy but some of the other things in OSVERSIONINFOEX you need to read from the registry or other source. Might be worthwhile in future versions; addinhg compatibility info to manifests is a pain. WMI isn't a great way to go about it since a lot of people have it disabled these days.
Ex:
Code:
Private Declare PtrSafe Function RtlGetCurrentPeb Lib "ntdll" () As LongPtr
Private Type LARGE_INTEGER
lowPart As Long
hiPart As Long
End Type
Private Type LIST_ENTRY
Flink As LongPtr
Blink As LongPtr
End Type
Private Type PEB
InheritedAddressSpace As Byte
ReadImageFileExecOptions As Byte
BeingDebugged As Byte
BitField As Byte
Mutant As LongPtr
ImageBaseAddress As LongPtr
Ldr As LongPtr
ProcessParameters As LongPtr 'RTL_USER_PROCESS_PARAMETERS, what we're primarily interested in.
SubSystemData As LongPtr
ProcessHeap As LongPtr
FastPebLock As LongPtr
AtlThunkSListPtr As LongPtr
SparePtr2 As LongPtr
EnvironmentUpdateCount As Long
KernelCallbackTable As LongPtr
SystemReserved(0) As Long
SpareUlong As Long
FreeList As LongPtr
TlsExpansionCounter As Long
TlsBitmap As LongPtr
TlsBitmapBits(1) As Long
ReadOnlySharedMemoryBase As LongPtr
ReadOnlySharedMemoryHeap As LongPtr
ReadOnlyStaticServerData As LongPtr
AnsiCodePageData As LongPtr
OemCodePageData As LongPtr
UnicodeCaseTableData As LongPtr
NumberOfProcessors As Long
NtGlobalFlag As Long
#If Win64 = 0 Then
Pad0 As Long
#End If
CriticalSectionTimeout As LARGE_INTEGER
HeapSegmentReserve As LongPtr
HeapSegmentCommit As LongPtr
HeapDeCommitTotalFreeThreshold As LongPtr
HeapDeCommitFreeBlockThreshold As LongPtr
NumberOfHeaps As Long
MaximumNumberOfHeaps As Long
ProcessHeaps As LongPtr
GdiSharedHandleTable As LongPtr
ProcessStarterHelper As LongPtr
GdiDCAttributeList As Long
LoaderLock As LongPtr
OSMajorVersion As Long
OSMinorVersion As Long
OSBuildNumber As Integer
OSCSDVersion As Integer
OSPlatformId As Long
ImageSubsystem As Long
ImageSubsystemMajorVersion As Long
ImageSubsystemMinorVersion As Long
ImageProcessAffinityMask As LongPtr
#If Win64 Then
GdiHandleBuffer(59) As Long
#Else
GdiHandleBuffer(33) As Long
#End If
PostProcessInitRoutine As LongPtr
TlsExpansionBitmap As LongPtr
TlsExpansionBitmapBits(31) As Long
SessionId As Long
AppCompatFlags As LARGE_INTEGER
AppCompatFlagUser As LARGE_INTEGER
pShimData As LongPtr
AppCompatInfo As LongPtr
CSDVersion As UNICODE_STRING
ActivationContextData As LongPtr
ProcessAssemblyStorageMap As LongPtr
SystemDefaultActivationContextData As LongPtr
SystemAssemblyStorageMap As LongPtr
MinimumStackCommit As LongPtr
#If Win64 Then
FlsCallback As LongPtr
FlsListHead As LIST_ENTRY
FlsBitmap As LongPtr
FlsBitmapBits(3) As Long
FlsHighIndex As Long
#Else
Pad1 As Long 'Make up for no LongLong
#End If
End Type
Private Sub ReadVerPeb(dwMajor As Long, dwMinor As Long, dwBuild As Integer, dwPlatformId As Long)
Dim lpPeb As LongPtr
Dim tPeb As PEB
lpPeb = RtlGetCurrentPeb()
If lpPeb Then
CopyMemory tPeb, ByVal lpPeb, LenB(tPeb)
dwMajor = tPeb.OSMajorVersion
dwMinor = tPeb.OSMinorVersion
dwBuild = tPeb.OSBuildNumber
dwPlatformId = tPeb.OSPlatformId
End If
End Sub
Also yeah sorry looks like I missed I debug output, thought I got them all. Had a bunch because it turned out twinBASIC had a bug where it was incorrectly calculating padding when a fixed array UDT was used in annother UDT and the first member was a pointer, while under x64. So I was going nuts for a bit thinking I had something wrong.
Last edited by fafalone; Oct 21st, 2023 at 08:59 PM.
I considered rewriting it to allocate dynamically, but due to the x64 differences and general complexity, figured it wouldn't be worth going there absent a bug report pointing to necessity.
I rewrote it with dynamic alloc. Hope there is no room to break something in x64 using the way I did it.
Code:
groupsCount = InfoBuffer(0)
ReDim tpGroups(groupsCount - 1) As SID_AND_ATTRIBUTES
Dim fieldOffset As Long: fieldOffset = Abs(VarPtr(tpTokens.Groups(0)) - VarPtr(tpTokens))
'Statically:
'"BufferSize" is much > SID_AND_ATTRIBUTES array, because
' the buffer returned also holds Sid strings data pointed by .Sid ptr of each array element
'So, we calculating array size manually:
'Call CopyMemory(tpTokens, InfoBuffer(0), fieldOffset + groupsCount * lenb(tpTokens.Groups(0)))
'Dynamically:
Call CopyMemory(tpGroups(0), InfoBuffer(fieldOffset), (UBound(tpGroups) + 1) * LenB(tpGroups(0)))
Also hope, there is no difference in that I took the 1st byte for groupsCount instead of DWORD.
But it wouldn't hurt to take another look. I haven't tested under x64 IDE.
Originally Posted by fafalone
One other thing I was looking at doing but ultimately didn't was rewriting to avoid the need for a manifest.
I'm using here RtlGetVersion instead of GetVersionExW. It doesn't suffer manifest-illness at least in my tests. So, Peb-based version is not necessary, although curious. Mentioning the manifest in 1st post is much like a rule of good manners. Though, Somebody reported it behaves differently, not sure what is his environments, anyway can't reproduce. And also, can't imagine one wants to do a normal application having no manifest, cos it's as easy as just adding resource with type #24 id 1, no scripts required.
RtlGetVersion pulls the same version lie on most systems unfortunately. I agree everyone *should* use manifests these days and I certainly do-- albeit rarely with the compatibility info section, just for cc6, but it's not too hard to eliminate that as a requirement. Just a couple other pieces of info to look up. The PEB method there is compatibile with XP+; cutting the UDT off at just the version info would probably allow earlier, if that's a concern. Probably not 9x/ME, but Win2k.
I'll test the update later on with x64 to make sure. It looks good though, since you're calculating the initial offset in a way that accounts for the extra padding in x64 there.
Ok tried it out, the code itself works, if you could just update it to this version, there were two small issues:
-The newly added PdhCloseQuery declare lacked the PtrSafe keyword in the If VBA7 block (hard error for x64), and not critical but ReDim tpGroups(groupsCount - 1) As SID_AND_ATTRIBUTES without a prior Dim is a considered a risky practice and triggers a warning in twinBASIC, so I added a Dim tpGroups() As SID_AND_ATTRIBUTES.
PS- If you update it in the future, the .twinproj isn't the same as a VBP (for now), it's a monolithic file and contains it's own copy, so that doesn't get updated just by updating the .cls. If you'd prefer not to keep that in sync, if you could perhaps direct twinBASIC users who want a .twinproj for it with a link to my repo for it and I'll keep that in sync with your releases here?
Last edited by fafalone; Oct 23rd, 2023 at 05:05 AM.
PS- If you update it in the future, the .twinproj isn't the same as a VBP (for now), it's a monolithic file and contains it's own copy, so that doesn't get updated just by updating the .cls. If you'd prefer not to keep that in sync, if you could perhaps direct twinBASIC users who want a .twinproj for it with a link to my repo for it and I'll keep that in sync with your releases here?
Ok, since you already published it on GitHub, it'll be ok to just mention your fork in my post as x64 IDE compatible, because it is possible you want to continue updating it, so not require my personal attention and sync each time, and anyway I still not much experienced in moving to x64 IDE. It was interesting for me to have a little start btw and to see how it works. However, I have no plans yet to move all my huge code base to tB.
Thank you for pointing the mistakes, and about .twinproj... yeah, I forgot it is self-included.
Yeah tB is getting awfully close but very large codebases will still have issues. For x64, I'd just note that it's entirely optional. tB supports 32bit, and the goal is no changes need to be made for existing code to run. Lots of code already does (see my sig). So I even bring in apps that will never be 64bit, since there's just so many new language features that we've been wanting in VB for so long... I'd say check it out once it hits 1.0-- that will mean most of the bugs impacting larger projects are gone and most common controls are implemented (or can be swapped with Krool's for a few that won't make it into 1.0).