Windows 8 and 8.1

Windows specific forum
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Windows 8 and 8.1

Post by IdeasVacuum »

http://www.codeproject.com/Articles/678 ... n-of-GetVe
Perhaps Fred can change the code behind OSVersion() to the code given in the above article.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Windows 8 and 8.1

Post by PB »

I laughed at the CodeProject link where they said this:

"It can take anywhere from 5-15 Milliseconds on a Physical System.
It took upward of 30 Milliseconds on a Virtual Machine to Execute.
Since This API can be can called many times during an Application's
life cycle [...]"


I mean, come on! You don't call this sort of thing over and over.
The OS isn't going to change during an app's runtime. Just call it
once, store the value, and you're done. :lol:
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Windows 8 and 8.1

Post by IdeasVacuum »

I really do think MS have lost the plot, it really does not have to be so complicated. They probably should have continued with GetVersionEx(), but for apps that only need to report the version, a simple string record would be fine. Any apps compiled for a lesser version could be automatically run in compatibility mode couldn't they? Then the 'Version Lie' would be redundant.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Windows 8 and 8.1

Post by luis »

I tried to see if it's possible to avoid to add a manifest to force GetVersionEx to not lie.

Can you test this different approach and tell me if it does work ?
From my tests it does.

PB 5.20

Code: Select all

Procedure.i GetOSVersion (*Major.Integer, *Minor.Integer, *Build.Integer)
; [DESC]
; Get the version number of the OS on which the program is running.
;
; [OUTPUT]
; *Major : The major version number (for example: 6).
; *Minor : The minor version number (for example: 1).
; *Build : The build number (for example: 7601).
;
; [RETURN]
; 1 if successful, else 0.

; see http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074%28v=vs.85%29.aspx
; see http://msdn.microsoft.com/en-us/library/windows/hardware/ff561910%28v=vs.85%29.aspx

; 6.1.7600 Win 7 
; 6.1.7601 Win 7 SP1
; 6.2.9200 Win 8.0
; 6.3.9600 Win 8.1

 Protected osvex.OSVERSIONINFOEX 
 Protected *fp, hDLL, major, minor, build
 Protected fail

 osvex\dwOSVersionInfoSize = SizeOf(osvex)
 
 fail = 1
 
 If GetVersionEx_(@osvex)
    fail = 0
    
    major = osvex\dwMajorVersion
    minor = osvex\dwMinorVersion 
    build = osvex\dwBuildNumber
        
    If (major = 6 And minor = 2) ; windows 8 ... we double check this
        fail = 1
        hDLL = OpenLibrary (#PB_Any, "ntdll.dll")      
        If hDLL    
            *fp = GetFunction(hDLL, "RtlGetVersion")
            If *fp And CallFunctionFast(*fp, @osvex) = 0 ; #STATUS_SUCCESS
                fail = 0
                major = osvex\dwMajorVersion    
                minor = osvex\dwMinorVersion
                build = osvex\dwBuildNumber
            EndIf     
            CloseLibrary(hDLL)        
        EndIf
    EndIf      
 EndIf      
 
 If fail
    *Major\i = 0
    *Minor\i = 0
    *Build\i = 0 
    ProcedureReturn 0
 Else
    *Major\i = major
    *Minor\i = minor
    *Build\i = build
    ProcedureReturn 1
 EndIf
EndProcedure


Define  maj, min, bld

Debug GetOSVersion(@maj, @min, @bld)

Debug "maj = " + maj
Debug "min = " + min
Debug "bld = " + bld
"Have you tried turning it off and on again ?"
A little PureBasic review
TassyJim
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Jun 16, 2013 6:27 am
Location: Tasmania (Australia)

Re: Windows 8 and 8.1

Post by TassyJim »

Results from W8.1 PB5.21B2

1
maj = 6
min = 3
bld = 9600

It seems to work.

Jim
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Windows 8 and 8.1

Post by RASHAD »

Nice snippet luis
With WMI we can get all what we need in one shot
In case WMI is stopped Run "net start winmgmt"
Tested with Win 8.1 x64

Code: Select all

; class Win32_OperatingSystem : CIM_OperatingSystem
; {
;   string   BootDevice;
;   string   BuildNumber;
;   string   BuildType;
;   string   Caption;
;   string   CodeSet;
;   string   CountryCode;
;   string   CreationClassName;
;   string   CSCreationClassName;
;   string   CSDVersion;
;   string   CSName;
;   sint16   CurrentTimeZone;
;   boolean  DataExecutionPrevention_Available;
;   boolean  DataExecutionPrevention_32BitApplications;
;   boolean  DataExecutionPrevention_Drivers;
;   uint8    DataExecutionPrevention_SupportPolicy;
;   boolean  Debug;
;   string   Description;
;   boolean  Distributed;
;   uint32   EncryptionLevel;
;   uint8    ForegroundApplicationBoost;
;   uint64   FreePhysicalMemory;
;   uint64   FreeSpaceInPagingFiles;
;   uint64   FreeVirtualMemory;
;   datetime InstallDate;
;   uint32   LargeSystemCache;
;   datetime LastBootUpTime;
;   datetime LocalDateTime;
;   string   Locale;
;   string   Manufacturer;
;   uint32   MaxNumberOfProcesses;
;   uint64   MaxProcessMemorySize;
;   string   MUILanguages[];
;   string   Name;
;   uint32   NumberOfLicensedUsers;
;   uint32   NumberOfProcesses;
;   uint32   NumberOfUsers;
;   uint32   OperatingSystemSKU;
;   string   Organization;
;   string   OSArchitecture;
;   uint32   OSLanguage;
;   uint32   OSProductSuite;
;   uint16   OSType;
;   string   OtherTypeDescription;
;   Boolean  PAEEnabled;
;   string   PlusProductID;
;   string   PlusVersionNumber;
;   boolean  PortableOperatingSystem;
;   boolean  Primary;
;   uint32   ProductType;
;   string   RegisteredUser;
;   string   SerialNumber;
;   uint16   ServicePackMajorVersion;
;   uint16   ServicePackMinorVersion;
;   uint64   SizeStoredInPagingFiles;
;   string   Status;
;   uint32   SuiteMask;
;   string   SystemDevice;
;   string   SystemDirectory;
;   string   SystemDrive;
;   uint64   TotalSwapSpaceSize;
;   uint64   TotalVirtualMemorySize;
;   uint64   TotalVisibleMemorySize;
;   string   Version;
;   string   WindowsDirectory;
; };


#COINIT_MULTITHREAD=0 
#RPC_C_AUTHN_LEVEL_CONNECT=2 
#RPC_C_IMP_LEVEL_IDENTIFY=2 
#EOAC_NONE=0 
#RPC_C_AUTHN_WINNT=10 
#RPC_C_AUTHZ_NONE=0 
#RPC_C_AUTHN_LEVEL_CALL=3 
#RPC_C_IMP_LEVEL_IMPERSONATE=3 
#CLSCTX_INPROC_SERVER=1 
#wbemFlagReturnImmediately=16 
#wbemFlagForwardOnly=32 
#IFlags = #wbemFlagReturnImmediately + #wbemFlagForwardOnly 
#WBEM_INFINITE=$FFFFFFFF 
#WMISeparator="," 

Procedure.l ansi2uni(ansi.s) 
  size.l=MultiByteToWideChar_(#CP_ACP,0,ansi,-1,0,0) 
  Dim unicode.w(size) 
  MultiByteToWideChar_(#CP_ACP, 0, ansi, Len(ansi), unicode(), size) 
  ProcedureReturn SysAllocString_(@unicode()) 
EndProcedure 

Procedure uni2ansi(uni) 
  Shared WMIResult.s 
  WMIResult.s = "" 
  mem=uni 
  While PeekW (mem) 
    WMIResult=WMIResult+Chr(PeekW(mem)) 
    mem=mem+2 
  Wend 
  ProcedureReturn @WMIResult 
EndProcedure 

ProcedureDLL.s WMI(WMICommand.s) 
  CoInitializeEx_(0,#COINIT_MULTITHREAD) 
  hres=CoInitializeSecurity_(0, -1,0,0,#RPC_C_AUTHN_LEVEL_CONNECT, #RPC_C_IMP_LEVEL_IDENTIFY,0,#EOAC_NONE,0) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoInitializeSecurity", #MB_OK): Goto cleanup: EndIf 
  hres=CoCreateInstance_(?CLSID_WbemLocator,0, #CLSCTX_INPROC_SERVER,?IID_IWbemLocator,@loc.IWbemLocator) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoCreateInstance", #MB_OK): Goto cleanup: EndIf
  
  CompilerIf #PB_Compiler_Unicode 
      hres=loc\ConnectServer(SysAllocString_(@"root\cimv2"),0,0,0,0,0,0,@svc.IWbemServices)
  CompilerElse  
      hres=loc\ConnectServer(ansi2uni("root\cimv2"),0,0,0,0,0,0,@svc.IWbemServices)
  CompilerEndIf

  If hres <> 0: MessageRequester("ERROR", "unable to call IWbemLocator::ConnectServer", #MB_OK): Goto cleanup: EndIf 
  hres=svc\QueryInterface(?IID_IUnknown,@pUnk.IUnknown) 
  hres=CoSetProxyBlanket_(svc,#RPC_C_AUTHN_WINNT, #RPC_C_AUTHZ_NONE,0,#RPC_C_AUTHN_LEVEL_CALL, #RPC_C_IMP_LEVEL_IMPERSONATE,0,#EOAC_NONE) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoSetProxyBlanket", #MB_OK): Goto cleanup: EndIf 
  hres=CoSetProxyBlanket_(pUnk,#RPC_C_AUTHN_WINNT, #RPC_C_AUTHZ_NONE,0,#RPC_C_AUTHN_LEVEL_CALL, #RPC_C_IMP_LEVEL_IMPERSONATE,0,#EOAC_NONE) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoSetProxyBlanket", #MB_OK): Goto cleanup: EndIf 
  pUnk\Release()
  
  k=CountString(WMICommand,#WMISeparator) 
  Dim wmitxt$(k) 
  For i=0 To k 
    wmitxt$(i) = StringField(WMICommand,i+1,#WMISeparator) 
  Next
   
  CompilerIf #PB_Compiler_Unicode
      hres=svc\ExecQuery(SysAllocString_(@"WQL"), SysAllocString_(@wmitxt$(0)), #IFlags,0,@pEnumerator.IEnumWbemClassObject) 
  CompilerElse 
      hres=svc\ExecQuery(ansi2uni("WQL"),ansi2uni(wmitxt$(0)), #IFlags,0,@pEnumerator.IEnumWbemClassObject)
  CompilerEndIf
   
  If hres <> 0: MessageRequester("ERROR", "unable to call IWbemServices::ExecQuery", #MB_OK): Goto cleanup: EndIf 
  hres=pEnumerator\reset() 
  Repeat 
  hres=pEnumerator\Next(#WBEM_INFINITE, 1, @pclsObj.IWbemClassObject, @uReturn) 
  For i=1 To k 
    mem=AllocateMemory(1000)
    
  CompilerIf #PB_Compiler_Unicode
    hres=pclsObj\get(SysAllocString_(@wmitxt$(i)), 0, mem, 0, 0)
  CompilerElse 
    hres=pclsObj\get(ansi2uni(wmitxt$(i)), 0, mem, 0, 0)
  CompilerEndIf
   
    Type=PeekW(mem) 
    Select Type 
      Case 8 
        val.s=PeekS(uni2ansi(PeekL(mem+8))) 
      Case 3 
        val.s=Str(PeekL(mem+8)) 
      Default 
        val.s="" 
    EndSelect 
    If uReturn <> 0: wmi$=wmi$+wmitxt$(i)+" = "+val+Chr(10)+Chr(13): EndIf 
    FreeMemory(mem) 
  Next 
Until uReturn = 0 

cleanup: 
svc\Release() 
loc\Release() 
pEnumerator\Release() 
pclsObj\Release() 
CoUninitialize_() 

ProcedureReturn wmi$ 
EndProcedure 


Text$ = WMI("Select * FROM Win32_OperatingSystem,Name")
Debug StringField(Text$,1, "|")
Debug WMI("Select * FROM Win32_OperatingSystem,Version")
Debug WMI("Select * FROM Win32_OperatingSystem,OSArchitecture")


DataSection 
CLSID_IEnumWbemClassObject: 
Data.l $1B1CAD8C 
Data.w $2DAB, $11D2 
Data.b $B6, $04, $00, $10, $4B, $70, $3E, $FD 

IID_IEnumWbemClassObject: 
Data.l $7C857801 
Data.w $7381, $11CF 
Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24 

CLSID_WbemLocator: 
Data.l $4590F811 
Data.w $1D3A, $11D0 
Data.b $89, $1F, $00, $AA, $00, $4B, $2E, $24 

IID_IWbemLocator: 
Data.l $DC12A687 
Data.w $737F, $11CF 
Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24 

IID_IUnknown: 
Data.l $00000000 
Data.w $0000, $0000 
Data.b $C0, $00, $00, $00, $00, $00, $00, $46 
EndDataSection 
Egypt my love
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Windows 8 and 8.1

Post by luis »

@TassyJim -> Thanks
@RASHAD -> Thanks, I try to avoid WMI if possible though... don't know really why, but another option is always welcomed :)
Thade wrote: I hopped with an USB-Stick and new copies of a program between my LapTop (Win 8.1) and another PC (Win 7) for half an hour until I noticed that the Program, which tested the OS Version was set to Win XP compatibility before. And every new version I copied over the old one had still this mode set.
I think that's because the compatibility mode for an EXE is stored in the registry, so every time you copy a new file over an older one the path it's still the same and so the new EXE just inherits the settings.

Code: Select all

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
PureGuy wrote: However, I think PB's OSVersion() functions should be updated.
I think too it should differentiate between 8.0 and 8.1.

If you ask someone "Are you using Windows 7 ?" and he's running Win 7 SP1 he would likely reply: "Yes".
If you ask someone "Are you using Windows 8 ?" and he's running Win 8.1 he would likely reply: "No 8.1".
"Have you tried turning it off and on again ?"
A little PureBasic review
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Windows 8 and 8.1

Post by c4s »

luis wrote:If you ask someone "Are you using Windows 8 ?" and he's running Win 8.1 he would likely reply: "No 8.1".
Well, I would say: "yes, Windows 8.1"... :wink:
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
smacker
User
User
Posts: 55
Joined: Thu Nov 06, 2014 7:18 pm

Re: Windows 8 and 8.1

Post by smacker »

Windows 8.1. and the up coming Windows 10 will only admit their real version if you program's manifest claims to be compatible. Otherwise, for example, Windows 8.1 will claim to be Windows 8. To get around this your 'program' has to claim to be compatible via its manifest. To solve this for Pure Basic a compatibility manifest needs to be added in the resources. This is the manifest outline Microsoft uses.

Code: Select all

<exe>.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <assemblyIdentity 
        type="win32" 
        name=SXS_ASSEMBLY_NAME
        version=SXS_ASSEMBLY_VERSION
        processorArchitecture=SXS_PROCESSOR_ARCHITECTURE
    />
    <description> my app exe </description>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel
                    level="asInvoker"
                    uiAccess="false"
                />	
            </requestedPrivileges>
        </security>
    </trustInfo>
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
        <application> 
         *  <!-- Windows 8.1 -->
         *  <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <!-- Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <!-- Windows 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
        </application> 
    </compatibility>
</assembly>


This is from > http://msdn.microsoft.com/en-us/library ... 85%29.aspx

where its noted on that page:
In Windows 8.1, the GetVersion(Ex) APIs have been deprecated. That means that while you can still call the APIs, if your app does not specifically target Windows 8.1, you will get Windows 8 versioning (6.2.0.0).
Which also means that if you are trying to get the version info for Windows 8.1 and it returns as windows 8 even though its really windows 8.1 that your 'app' or the method being used to get the windows version does not include the 'required' manifest information to specifically target windows 8.1.

That's why the old tried and true methods people have used in Pure Basic return windows 8 for what is really windows 8.1.
The world and human nature was screwed up before I was born. It's not my fault and I'm just stuck with trying to deal with the mess left behind, so don't blame me.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Windows 8 and 8.1

Post by luis »

@smacker

Wasn't all this and more already stated in the thread, link included :?:
"Have you tried turning it off and on again ?"
A little PureBasic review
smacker
User
User
Posts: 55
Joined: Thu Nov 06, 2014 7:18 pm

Re: Windows 8 and 8.1

Post by smacker »

This is my first version from that link mentioned by IdeasVacuum further back in this thread (http://www.codeproject.com/Articles/678 ... n-of-GetVe) - wanted to check out the viability of using it.

can someone test this for Windows 8 and and 8.1, and if you have the preview build of Windows 10 on that also?

note that it only calls the ansi version of the VerifyVersionInfo function from the API, make the necessary corrections if you want unicode and call the unicode version, yes, I could have done the CompilerIf thing but I didn't here.

Code: Select all

Prototype PVerifyVersionInfo(lpVersionInfo.l, dwTypeMask.l, dwlConditionMask.q) : Global VerifyVersionInfo.PVerifyVersionInfo
Prototype PRtlZeroMemory(mem, sze) : Global ZeroMemory.PRtlZeroMemory
Prototype PVerSetConditionMask(in_ULONGLONG_dwlConditionMask.q, in_DWORD_dwTypeBitMask.l, in_BYTE_dwConditionMask.b)
Global VerSetConditionMask.PVerSetConditionMask

Lib_Kernel32 = OpenLibrary(#PB_Any, "Kernel32.dll")
If IsLibrary(Lib_Kernel32)
  isLib_Kernel32.b = #True
  VerifyVersionInfo.PVerifyVersionInfo=GetFunction(Lib_Kernel32,"VerifyVersionInfoA")
  VerSetConditionMask.PVerSetConditionMask=GetFunction(Lib_Kernel32,"VerSetConditionMask")
  ZeroMemory.PRtlZeroMemory=GetFunction(Lib_Kernel32,"RtlZeroMemory")
Else
  isLib_Kernel32.b = #False
EndIf

#VER_MINORVERSION = $0000001
#VER_MAJORVERSION = $0000002
#VER_SERVICEPACKMINOR = $0000010
#VER_SERVICEPACKMAJOR = $0000020

#VER_BUILDNUMBER  = $0000004
#VER_MAJORVERSION = $0000002
#VER_MINORVERSION = $0000001
#VER_PLATFORMID = $0000008
#VER_PRODUCT_TYPE = $0000080
#VER_SERVICEPACKMAJOR = $0000020
#VER_SERVICEPACKMINOR = $0000010
#VER_SUITENAME = $0000040

#VER_EQUAL = 1 ; The current value must be equal to the specified value..
#VER_GREATER = 2 ; The current value must be greater than the specified value.
#VER_GREATER_EQUAL = 3 ; The current value must be greater than or equal to the specified value.
#VER_LESS = 4 ; The current value must be less than the specified value.
#VER_LESS_EQUAL = 5 ; The current value must be less than or equal to the specified value.

; for VerSetConditionMask function if dwTypeBitMask is #VER_SUITENAME the dwConditionMask parameter can be one of the following values.
#VER_AND = 6 ; All product suites specified in the wSuiteMask member must be present in the current system.
#VER_OR = 7  ; At least one of the specified product suites must be present in the current system.

Procedure TestOSVersion(major.l, minor.l, prodtype.b)
  
  osvi.OSVERSIONINFOEX
  dwlConditionMask.q = 0
  
  ; dwMajorVersion for windows 7, 8, 8.1, and 10 are all 6 so we really only need to check for the minor version
  ; but we use a procedure input here so its not hard coded so can be changed in case we want to test for other versions
  osvi\dwOSVersionInfoSize = SizeOf(OSVERSIONINFOEX)
  osvi\dwMajorVersion = major
  osvi\dwMinorVersion = minor
  ;wversion\dwMinorVersion = 0 for Windows Vista, and Windows Server 2008
  ;wversion\dwMinorVersion = 1 for Windows 7, and Windows Server 2008 R2
  ;wversion\dwMinorVersion = 2 for Windows 8, and Windows Server 2012
  ;wversion\dwMinorVersion = 3 for Windows 8.1, and Windows Server 2012 R2
  ;wversion\dwMinorVersion = 4 for Windows 10
  osvi\wProductType = prodtype ; #VER_NT_SERVER ; or #VER_NT_WORKSTATION depending on if we test for workstation or server
  ; for example:
  ; major/minor on windows server 2008 R2 is same as windows 7 workstation so we need to diffrentiate via prodtype variable input
  ; major/minor on Windows Server 2012 is same as Windows 8 workstation so we need to diffrentiate via prodtype variable input
  ; major/minor on Windows Server 2012 R2 is same as windows 8.1 workstation so we need to diffrentiate via prodtype variable input
  
  dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_MAJORVERSION, #VER_EQUAL)
  dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_MINORVERSION, #VER_EQUAL)
  dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_PRODUCT_TYPE, #VER_EQUAL)
  
  isorisnotos = VerifyVersionInfo(osvi, #VER_MAJORVERSION|#VER_MINORVERSION|#VER_PRODUCT_TYPE, dwlConditionMask)
  ; If the operating system this is run in satisfies the specified requirements in the procedure input parameters the return value is a nonzero value.
  ; If the operating system this is run in does not satisfy the specified requirements in the procedure input parameters the return value is zero
  ProcedureReturn isorisnotos
  
EndProcedure

Debug TestOSVersion(6, 0, #VER_NT_WORKSTATION) ;Windows Vista
Debug TestOSVersion(6, 0, #VER_NT_SERVER)      ;Windows Vista

Debug TestOSVersion(6, 1, #VER_NT_WORKSTATION) ;Windows 7
Debug TestOSVersion(6, 1, #VER_NT_SERVER)      ;Windows 7

Debug TestOSVersion(6, 2, #VER_NT_WORKSTATION) ;Windows 8
Debug TestOSVersion(6, 2, #VER_NT_SERVER)      ;Windows 8

Debug TestOSVersion(6, 3, #VER_NT_WORKSTATION) ;Windows 8.1
Debug TestOSVersion(6, 3, #VER_NT_SERVER)      ;Windows 8.1

Debug TestOSVersion(6, 4, #VER_NT_WORKSTATION) ;Windows 10
Debug TestOSVersion(6, 4, #VER_NT_SERVER) ;Windows 10
Microsoft , and others examples i've seen, uses a macro called VER_SET_CONDITION instead of calling the VerSetConditionMask function directly each time. The macro just calls VerSetConditionMask function some way or another anyway from what i've read. So here is the macro instead if you want to use it:

Code: Select all

Macro VER_SET_CONDITION(ConditionMask, VER, op)
  VerSetConditionMask(ConditionMask, VER, op)
EndMacro
to use the macro insert it above the procedure, you still need to call it for each test condition so for the above code replace these lines:

Code: Select all

dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_MAJORVERSION, #VER_EQUAL)
dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_MINORVERSION, #VER_EQUAL)
dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_PRODUCT_TYPE, #VER_EQUAL)


with these:

Code: Select all

dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, #VER_MAJORVERSION, #VER_EQUAL)
dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, #VER_MINORVERSION, #VER_EQUAL)
dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, #VER_PRODUCT_TYPE, #VER_EQUAL)
It seems to work compiled 64 bit Windows 7, but does not work when compiled 32 bit in Windows 7 and VerifyVersionInfo comes back with error code 1150 (using GetLastError) which translates to "The specified program requires a newer version of Windows." so i'm not sure if thats because it does not work in 32 bit at all or there is something else odd going on. I haven't read anything yet which indicates its 64 bit only.

Here is another version for testing, its a version of the ' IsWindows7OrGreater' version helper functions from the API which can't be called directly from the dll in Pure Basic > http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Code: Select all

Procedure IsWindows7OrGreater(prodtype.b)
  
  osvi.OSVERSIONINFOEX
  dwlConditionMask.q = 0
  
  ; dwMajorVersion for windows 7, 8, 8.1, and 10 are all 6 so we really only need to check for the minor version
  ; but we use a procedure input here so its not hard coded so can be changed in case we want to test for other versions
  osvi\dwOSVersionInfoSize = SizeOf(OSVERSIONINFOEX)
  osvi\dwMajorVersion = 6
  osvi\dwMinorVersion = 1
  ;wversion\dwMinorVersion = 0 for Windows Vista, and Windows Server 2008
  ;wversion\dwMinorVersion = 1 for Windows 7, and Windows Server 2008 R2
  ;wversion\dwMinorVersion = 2 for Windows 8, and Windows Server 2012
  ;wversion\dwMinorVersion = 3 for Windows 8.1, and Windows Server 2012 R2
  ;wversion\dwMinorVersion = 4 for Windows 10
  osvi\wProductType = prodtype ; #VER_NT_SERVER ; or #VER_NT_WORKSTATION depending on if we test for workstation or server
  ; for example:
  ; major/minor on windows server 2008 R2 is same as windows 7 workstation so we need to diffrentiate via prodtype variable input
  ; major/minor on Windows Server 2012 is same as Windows 8 workstation so we need to diffrentiate via prodtype variable input
  ; major/minor on Windows Server 2012 R2 is same as windows 8.1 workstation so we need to diffrentiate via prodtype variable input
  
  dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, #VER_MAJORVERSION, #VER_GREATER_EQUAL)
  dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, #VER_MINORVERSION, #VER_GREATER_EQUAL)
  dwlConditionMask = VER_SET_CONDITION(dwlConditionMask, #VER_PRODUCT_TYPE, #VER_EQUAL)
    
  isorisnotos = VerifyVersionInfo(osvi, #VER_MAJORVERSION|#VER_MINORVERSION|#VER_PRODUCT_TYPE, dwlConditionMask)
  
  ; If the operating system this is run in satisfies the specified requirements the return value is a nonzero value.
  ; If the operating system this is run in does not satisfy the specified requirements the return value is zero
  ProcedureReturn isorisnotos
  
EndProcedure

Debug IsWindows7OrGreater(#VER_NT_WORKSTATION)


So, if someone could check it out and see how it works out for windows 8 and 8.1 .... don't have access to a windows 8 machine right now, waiting for a new hard drive to arrive for it.

thanks
The world and human nature was screwed up before I was born. It's not my fault and I'm just stuck with trying to deal with the mess left behind, so don't blame me.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Windows 8 and 8.1

Post by luis »

luis wrote: Wasn't all this and more already stated in the thread, link included :?:
I'll take it as a YES. But after all it was a rethorical question.


VerifyVersionInfo() could be useful if you want to test for more than just the version/build, but if you just need the version number I think it's A LOT simpler to just call RtlGetVersion() -> http://www.purebasic.fr/english/viewtop ... 21#p431121

When called from PB in user mode (from ntdll.dll) RtlGetVersion() switches the current thread in kernel mode to jump to its actual implementation in kernel code (the real mode code is just a "stub" where the address of the real function inside ntoskrnl.exe is loaded).
At that point since MS have not yet considered to screw up the answers one can get from this family of functions the code inside the kernel retrieve the real OS version, not exactly from the internal kernel structures as one could hope because seeing the thread is originally coming from user mode it just uses the process environment block initialized at process creation, still containing for now the correct data (see OSMajorVersion, OSMinorVersion, OSBuildNumber from http://en.wikipedia.org/wiki/Process_Environment_Block).
As long you don't call GetVersionEx() which wraps RtlGetVersion() poisoning its result if Windows > 8 and go directly to the source instead, you should be safe for the time being and get a straight answer to the simple question: what is the OS version ?

About your questions:
smacker wrote: can someone test this for Windows 8 and and 8.1, and if you have the preview build of Windows 10 on that also?
I've tested it under win7 x64 and win8.1 x64 and it does seem to work compiled as 32 and 64 bits (after the correction below).
smacker wrote: It seems to work compiled 64 bit Windows 7, but does not work when compiled 32 bit in Windows 7 and VerifyVersionInfo comes back with error code 1150 (using GetLastError) which translates to "The specified program requires a newer version of Windows." so i'm not sure if thats because it does not work in 32 bit at all or there is something else odd going on. I haven't read anything yet which indicates its 64 bit only.
There was an error in the prototypes.
VerSetConditionMask() returns and unsigned quad so it worked under x64 where the default return type is a 64 bit integer, on x86 was truncated and you lost the upper 32 bits, so it was working with some flags (the ones using the lower 32 bits) and not with others.
Also you don't need to be so strict with .l and .b in both prototypes and code (but you can if you wish), you can just use the base integer type everywhere avoiding conversions back and forth until the values are assigned where it counts (with a transparent one time truncation like in the case of OSVERSIONINFOEX assignments).

Code: Select all

EnableExplicit

Prototype.i PVerifyVersionInfo (*lpVersionInfo, dwTypeMask, dwlConditionMask.q) : Global VerifyVersionInfo.PVerifyVersionInfo
Prototype.q PVerSetConditionMask (in_ULONGLONG_dwlConditionMask.q, in_DWORD_dwTypeBitMask, in_BYTE_dwConditionMask) : Global VerSetConditionMask.PVerSetConditionMask

Global Lib_Kernel32 = OpenLibrary(#PB_Any, "Kernel32.dll")

If IsLibrary(Lib_Kernel32)    
CompilerIf (#PB_Compiler_Unicode = 1)
    VerifyVersionInfo.PVerifyVersionInfo=GetFunction(Lib_Kernel32,"VerifyVersionInfoW")
CompilerElse
    VerifyVersionInfo.PVerifyVersionInfo=GetFunction(Lib_Kernel32,"VerifyVersionInfoA")
CompilerEndIf
    VerSetConditionMask.PVerSetConditionMask=GetFunction(Lib_Kernel32,"VerSetConditionMask")
EndIf

#VER_MINORVERSION = $0000001
#VER_MAJORVERSION = $0000002
#VER_BUILDNUMBER  = $0000004
#VER_PLATFORMID = $0000008
#VER_SERVICEPACKMINOR = $0000010
#VER_SERVICEPACKMAJOR = $0000020
#VER_PRODUCT_TYPE = $0000080
#VER_SUITENAME = $0000040

#VER_EQUAL = 1 ; The current value must be equal to the specified value..
#VER_GREATER = 2 ; The current value must be greater than the specified value.
#VER_GREATER_EQUAL = 3 ; The current value must be greater than or equal to the specified value.
#VER_LESS = 4 ; The current value must be less than the specified value.
#VER_LESS_EQUAL = 5 ; The current value must be less than or equal to the specified value.

; for VerSetConditionMask function if dwTypeBitMask is #VER_SUITENAME the dwConditionMask parameter can be one of the following values.
#VER_AND = 6 ; All product suites specified in the wSuiteMask member must be present in the current system.
#VER_OR = 7  ; At least one of the specified product suites must be present in the current system.

Procedure.i TestOSVersion(major, minor, prodtype)
  Protected osvi.OSVERSIONINFOEX
  Protected dwlConditionMask.q
  Protected isorisnotos 
  
  osvi\dwOSVersionInfoSize = SizeOf(OSVERSIONINFOEX)
  osvi\dwMajorVersion = major
  osvi\dwMinorVersion = minor
  osvi\wProductType = prodtype ; #VER_NT_SERVER ; or #VER_NT_WORKSTATION depending on if we test for workstation or server
 
  dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_MAJORVERSION, #VER_EQUAL)
  dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_MINORVERSION, #VER_EQUAL)
  dwlConditionMask = VerSetConditionMask(dwlConditionMask, #VER_PRODUCT_TYPE, #VER_EQUAL)
 
  isorisnotos = VerifyVersionInfo(@osvi, #VER_MAJORVERSION|#VER_MINORVERSION|#VER_PRODUCT_TYPE, dwlConditionMask)

  ProcedureReturn isorisnotos
EndProcedure


Debug TestOSVersion(6, 1, #VER_NT_WORKSTATION) ; Windows 7
Debug TestOSVersion(6, 1, #VER_NT_SERVER)      ; Windows 7
Debug TestOSVersion(6, 3, #VER_NT_WORKSTATION) ; Windows 8.1
Debug TestOSVersion(6, 3, #VER_NT_SERVER)      ; Windows 8.1
As a side note, depending on what you mean by server could be better to test for it not using a logic like "= #VER_NT_SERVER" but instead "<> #VER_NT_WORKSTATION", since another possible value beyond #VER_NT_WORKSTATION and #VER_NT_SERVER is #VER_NT_DOMAIN_CONTROLLER, and that one is still a SERVER.
Last edited by luis on Mon Nov 10, 2014 8:59 pm, edited 1 time in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
smacker
User
User
Posts: 55
Joined: Thu Nov 06, 2014 7:18 pm

Re: Windows 8 and 8.1

Post by smacker »

Thanks luis, that's great :)
The world and human nature was screwed up before I was born. It's not my fault and I'm just stuck with trying to deal with the mess left behind, so don't blame me.
User avatar
Teddy Rogers
User
User
Posts: 98
Joined: Sun Feb 23, 2014 2:05 am
Location: Australia
Contact:

Re: Windows 8 and 8.1

Post by Teddy Rogers »

RtlGetVersion routine works fine as an alternative...

Code: Select all

Procedure.s RtlGetVersion()
  Protected RTL.OSVERSIONINFOEX                                 ; RTL Structure
  
  RTL\dwOSVersionInfoSize = SizeOf(RTL)                         ; The size, in bytes, of an RTL_OSVERSIONINFOEX structure
  
  ntdll = OpenLibrary(#PB_Any,"ntdll.dll")
 
  If ntdll
    *RtlGetVersion = GetFunction(ntdll,"RtlGetVersion")
    
    If *RtlGetVersion
      CallFunctionFast(*RtlGetVersion, @RTL)
    EndIf
    
    CloseLibrary(ntdll)
  EndIf
  
  ProcedureReturn Str(RTL\dwMajorVersion) + "." + Str(RTL\dwMinorVersion) + "." + Str(RTL\dwBuildNumber)
EndProcedure

Debug RtlGetVersion()
Ted.
smacker
User
User
Posts: 55
Joined: Thu Nov 06, 2014 7:18 pm

Re: Windows 8 and 8.1

Post by smacker »

yes, RtlGetVersion() is ok to use but it should be noted that the RtlGetVersion() seems to only works properly "fully" when compiled unicode when using the OSVERSIONINFOEX structure. For example, in ansi compile the 'wProductType' return will always be 0 where in unicode compile the 'wProductType' will return as what the version product type actually is, for example, #VER_NT_WORKSTATION or #VER_NT_SERVER or #VER_NT_DOMAIN_CONTROLLER, for OS with the same version, for example, Windows 7 is version 6.1 and Windows Server 2008 R2 is version 6.1 also.
The world and human nature was screwed up before I was born. It's not my fault and I'm just stuck with trying to deal with the mess left behind, so don't blame me.
Post Reply